-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
9d06701
commit 79067f4
Showing
4 changed files
with
219 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
module Kodfodrasz.AoC.Year2024.Tests.Day9Tests | ||
|
||
open Xunit | ||
open Swensen.Unquote.Assertions | ||
|
||
open Kodfodrasz.AoC | ||
open Kodfodrasz.AoC.Year2024 | ||
open Kodfodrasz.AoC.Year2024.Day9 | ||
|
||
|
||
let exampleInput = """ | ||
2333133121414131402 | ||
""" | ||
|
||
[<Fact>] | ||
let ``Parsing example input`` () = | ||
let expected = [| | ||
File (0, 2, 0) | ||
Free (2, 3) | ||
File (5, 3, 1) | ||
Free (8, 3) | ||
File (11, 1, 2) | ||
Free (12, 3) | ||
File (15, 3, 3) | ||
Free (18, 1) | ||
File (19, 2, 4) | ||
Free (21, 1) | ||
File (22, 4, 5) | ||
Free (26, 1) | ||
File (27, 4, 6) | ||
Free (31, 1) | ||
File (32, 3, 7) | ||
Free (35, 1) | ||
File (36, 4, 8) | ||
Free (40, 0) | ||
File (40, 2, 9) | ||
|] | ||
|
||
test | ||
<@ let actual = parseInput exampleInput | ||
actual = Ok expected @> | ||
|
||
|
||
[<Fact>] | ||
let ``Parsing example input for 12345`` () = | ||
test | ||
<@ | ||
let expected = Ok [| | ||
File (0, 1, 0) | ||
Free (1, 2) | ||
File (3, 3, 1) | ||
Free (6, 4) | ||
File (10, 5, 2) | ||
|] | ||
let actual = parseInput "12345" | ||
actual = expected | ||
@> | ||
|
||
[<Fact>] | ||
let ``Answer 1 for example input for 12345`` () = | ||
let blocks = parseInput "12345" |> Result.get | ||
// BLOCKS BEFORE: 0..111....22222 | ||
// BLOCKS AFTER : 022111222 | ||
// POS : 0123456789 | ||
// CHECKSUM : 60 = 0 + 2 + 4 + 3 + 4 + 5 + 12 + 14 + 16 | ||
test <@ answer1 blocks = Ok 60L @> | ||
|
||
[<Fact>] | ||
let ``Answer 1 for example input`` () = | ||
let input = parseInput exampleInput | ||
|
||
test | ||
<@ let actual = Result.bind answer1 input | ||
let expected: Result<_, string> = Ok 1928L | ||
actual = expected @> | ||
|
||
[<Fact(Skip="TODO")>] | ||
let ``Answer 2 for example input`` () = | ||
let input = parseInput exampleInput | ||
|
||
test | ||
<@ let actual = Result.bind answer2 input | ||
let expected: Result<_, string> = Ok 31L | ||
actual = expected @> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
module Kodfodrasz.AoC.Year2024.Day9 | ||
|
||
open System | ||
open System.Text.RegularExpressions | ||
open Kodfodrasz.AoC | ||
open System.Collections.Generic | ||
|
||
type Block = | ||
| File of pos : int * size : int * id : int | ||
| Free of pos : int * size : int | ||
|
||
let pos = function | ||
| File(pos, _, _) -> pos | ||
| Free(pos, _) -> pos | ||
|
||
let size = function | ||
| File(_, size, _) -> size | ||
| Free(_, size) -> size | ||
|
||
let fid = function | ||
| File(_, _, _id) -> _id | ||
| Free(_, _) -> failwith "Not a file" | ||
|
||
type BlockPosComparer() = | ||
interface IComparer<Block> with | ||
member _.Compare(x, y) = | ||
compare (pos x) (pos y) | ||
|
||
type parsedInput = Block array | ||
let parseInput (input: string): Result<parsedInput,string> = | ||
let numbers = | ||
input.Split('\n', StringSplitOptions.TrimEntries ||| StringSplitOptions.RemoveEmptyEntries) | ||
|> Seq.collect(String.toCharArray) | ||
|> Seq.map (string >> int) | ||
|> Seq.toArray | ||
|
||
let blocks = | ||
numbers | ||
|> Array.fold (fun (id, pos, l) n -> | ||
match l with | ||
| [] | Free _ :: _ -> | ||
let f = File(pos, n, id) | ||
(id + 1, pos + n, f :: l) | ||
| File _ :: _-> | ||
let f = Free(pos, n) | ||
(id, pos + n, f :: l) | ||
) (0, 0, List.empty) | ||
|> (fun (_, _, l) -> List.rev l) | ||
|
||
blocks | ||
|> List.toArray | ||
|> Ok | ||
|
||
let checksum blocks = | ||
Seq.sumBy(function | ||
| File(pos, size, id) -> | ||
let mutable sum = 0L | ||
for x in 0 .. size - 1 do | ||
sum <- sum + int64(pos + x) * int64(id) | ||
sum | ||
| Free _ -> 0 | ||
) blocks | ||
|
||
let defrag1 blocks : Block array = | ||
let blocks = System.Collections.Generic.List<Block>(blocks :> Block seq) | ||
|
||
let cmp = BlockPosComparer() | ||
let mutable fragmented = true | ||
while fragmented do | ||
let firstFreeIdx = blocks.FindIndex(function | ||
| Free (pos, size) -> size > 0 | ||
| _ -> false) | ||
let lastFileIdx = blocks.FindLastIndex(function | ||
| File(pos, size, id) -> true | ||
| _ -> false) | ||
|
||
fragmented <- firstFreeIdx >= 0 && lastFileIdx >= 0 | ||
|
||
if fragmented then | ||
let free = blocks[firstFreeIdx] | ||
let file = blocks[lastFileIdx] | ||
|
||
if pos free > pos file then | ||
blocks.RemoveAt(firstFreeIdx) | ||
elif size free = size file then | ||
blocks[firstFreeIdx] <- File( | ||
pos free, | ||
size file, | ||
fid file) | ||
blocks.RemoveAt(lastFileIdx) | ||
elif size free > size file then | ||
blocks[lastFileIdx] <- File( | ||
pos free, | ||
size file, | ||
fid file) | ||
blocks[firstFreeIdx] <- Free( | ||
pos free + size file, | ||
size free - size file) | ||
else // file is bigger | ||
blocks[firstFreeIdx] <- File( | ||
pos free, | ||
size free, | ||
fid file) | ||
blocks[lastFileIdx] <- File( | ||
pos file, | ||
size file - size free, | ||
fid file) | ||
blocks.Sort(cmp) | ||
|
||
blocks.ToArray() | ||
|
||
let answer1 (blocks : parsedInput) = | ||
blocks | ||
|> defrag1 | ||
|> checksum | ||
|> Ok | ||
|
||
let answer2 (data : parsedInput) = | ||
failwith "TODO" | ||
|
||
type Solver() = | ||
inherit SolverBase("Disk Fragmenter") | ||
with | ||
override this.Solve input = | ||
input | ||
|> | ||
this.DoSolve | ||
(parseInput) | ||
[ | ||
answer1; | ||
answer2; | ||
] | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters