summary refs log blame commit diff stats
path: root/day16.fsx
blob: 6b6de0cb680f1460e8eb0c3ee7b5cf9c3d8b7d0d (plain) (tree)



























































                                                                                                          
open System.IO
open System.Text.RegularExpressions

type Move =
    | Spin of offset: int
    | Exchange of first: int * second: int
    | Partner of first: char * second: char

let (|MoveRegex|_|) pattern input=
    let m = Regex(pattern).Match(input)
    if m.Success then Some(List.tail [for x in m.Groups -> x.Value])
    else None

let parseMove str =
    match str with
    | MoveRegex "s(\d+)" [x] -> Spin(int x)
    | MoveRegex "x(\d+)/(\d+)" [x; y] -> Exchange(int x, int y)
    | MoveRegex "p(\w)/(\w)" [x; y] -> Partner(char x, char y)
    | _ -> failwith "invalid input"

let swapPos x y (chars: char array) =
    chars |> Array.mapi (fun i v -> 
                            match i with
                            | _ when i = x -> chars.[y]
                            | _ when i = y -> chars.[x]
                            | _ -> v)

let swapLetter x y (chars: char array) =
    let indexOf elem = chars |> Array.findIndex((=) elem)
    swapPos (indexOf x) (indexOf y) chars

let spinChars steps (str: char array) =
    let startIndex = str.Length - steps
    let first, last = str[..startIndex - 1], str[startIndex..]
    Array.append last first

let executeMove chars move =
    match move with
    | Spin x -> spinChars x chars
    | Exchange (x, y) -> swapPos x y chars
    | Partner (x, y) -> swapLetter x y chars

let rec executeMoves state moves seen =
    let newState = Array.fold executeMove state moves
    if List.contains newState seen then
        let r = List.rev seen
        let l = List.length seen
        let m = 1000000000 % l
        r.[m]
    else
        executeMoves newState moves (newState :: seen)

let () =
    let moves = (File.ReadAllText "day16.txt").Trim().Split(',') |> Array.map parseMove
    let initialState = ("abcdefghijklmnop" |> Array.ofSeq)
    let finalState = Array.fold executeMove initialState moves
    // part 1
    finalState |> Array.map string |> String.concat "" |> printfn "%s"
    // part 2
    executeMoves initialState moves [initialState] |> Array.map string |> String.concat "" |> printfn "%s"