Here's the right challenge. This was a lot simpler than the tracking of cycles.
type Direction = Left | Right
type Instruction = { Direction: Direction; Distance: int }
let parseInstruction (segment:string) =
let direction = if segment[0] = 'L' then Left else Right
let distance = Int32.Parse(segment.AsSpan().Slice(1))
{ Direction = direction; Distance = distance }
let inline normalize (array: 'a array) idx =
if idx >= 0 then idx % array.Length else array.Length - (-idx % array.Length)
let inline nextIndex instruction idx =
match instruction.Direction with
| Left -> idx - instruction.Distance
| Right -> idx + instruction.Distance
let readFile file =
File.ReadAllLines(file)
|> fun lines ->
let names = lines.[0] |> _.Split(",", StringSplitOptions.RemoveEmptyEntries ||| StringSplitOptions.TrimEntries)
let instructions =
lines[2]
|> _.Split(",", StringSplitOptions.RemoveEmptyEntries ||| StringSplitOptions.TrimEntries)
|> Array.map parseInstruction
(names, instructions)
let part1File file : string =
readFile file
|> fun (names, instructions) ->
instructions
|> Seq.fold (fun (idx, _) instruction ->
let next = nextIndex instruction idx |> fun v -> Math.Clamp(v, 0, names.Length - 1)
match Array.tryItem next names with
| Some n -> next, n
| None -> failwith "off array"
) (0, "")
|> snd
let part1 () = part1File "Inputs/Quest01/Q01_P01.txt"
let part2File file =
readFile file
|> fun (names, instructions) ->
instructions
|> Seq.fold (fun (idx, _) instruction ->
let next = nextIndex instruction idx |> normalize names
match Array.tryItem next names with
| Some n -> next, n
| None -> failwith "off array"
) (0, "")
|> snd
let part2() = part2File "Inputs/Quest01/Q01_P02.txt"
let part3File file =
readFile file
|> fun (names, instructions) ->
// need to preserve a reference to an array that can be mutated
let mutable nameArray = names
instructions
|> Seq.fold (fun _ instruction ->
// for this challenge the index doesn't matter
let next = match instruction.Direction with
| Left -> names.Length - instruction.Distance
| Right -> instruction.Distance
|> normalize names
match Array.tryItem next nameArray with
| Some n ->
nameArray <- arraySwap 0 next names
0, n
| None -> failwith "off array"
) (0, "")
|> snd
let part3() = part3File "Inputs/Quest01/Q01_P03.txt"