• 2 Posts
  • 11 Comments
Joined 3 months ago
cake
Cake day: July 30th, 2025

help-circle
  • FSharp
    (my first submission failed, so I may not be as detailed here)

    I laugh at how long this took me. At first I got stuck due to checked arithmetic. In FSharp you open the Checked module and you get the overloaded operators for primitives, whereas CSharp is checked {a + b}. I also mistakenly used distinct on part 3 when I didn’t need it.

    I did appreciate the choose functions of functional programming, which returns all of the Some values of a sequence of options. The PSeq library let me use 70% of the cpu on the calculations :)

    module EveryBodyCodes2025.Quest02  
    
    open System.IO  
    open System.Text.RegularExpressions  
    open FSharp.Collections.ParallelSeq  
    open Checked  
    
    [<Struct>]  
    type ComplexNumber = 
        {X: int64; Y: int64}  
        static member (+) (a: ComplexNumber, b: ComplexNumber) = {X = a.X + b.X; Y = a.Y + b.Y }  
        static member (*) (a: ComplexNumber, b: ComplexNumber) = { X = ( a.X * b.X ) - (a.Y * b.Y); Y = (a.X * b.Y) + (a.Y * b.X) }  
        static member (/) (a: ComplexNumber, b: ComplexNumber) = { X = a.X / b.X; Y = a.Y / b.Y }  
        override this.ToString() = $"[{this.X},{this.Y}]"  
        
    let parseInput file =  
        File.ReadAllLines file  
        |> fun lines ->  
            let reg = Regex(@"A=\[(-?\d+),(-?\d+)\]")  
            let res = reg.Match(lines[0])  
            match res.Success with  
            | true ->  
                let x = int64 res.Groups[1].Value  
                let y = int64 res.Groups[2].Value  
                {X = x; Y = y}  
            | false -> failwith "failed to parse"  
            
        
    let part1 () =  
        parseInput "Inputs/Quest02/Q02_P01.txt"  
        |> fun a ->  
            [1..3]  
            |> List.fold (fun acc _ -> (acc * acc) / { X = 10; Y = 10 } + a ) {X = 0; Y = 0}  
    
    let cycle p =  
        let rec iterate current iteration =  
            if iteration = 100 then Some current  
            else  
                let next = (current * current) / {X = 100_000; Y = 100_000 } + p  
                if abs(next.X) > 1_000_000 || abs(next.Y) > 1_000_000 then  
                    None  
                else iterate next (iteration + 1)  
        iterate { X = 0; Y = 0 } 0  
    
    let part2 () =  
        parseInput "Inputs/Quest02/Q02_P02.txt"  
        |> fun a ->  
            seq {  
                for y in 0..100 do  
                for x in 0..100 do  
                    yield {X = a.X + (int64 x * 10L); Y = a.Y + (int64 y * 10L)}  
            }  
            |> PSeq.choose cycle  
            |> PSeq.distinct  
            |> PSeq.length  
    
    let part3 () =  
        parseInput "Inputs/Quest02/Q02_P03.txt"  
        |> fun a ->  
            seq {  
                for y in 0..1000 do  
                for x in 0..1000 do  
                    yield {X = a.X + (int64 x); Y = a.Y + (int64 y)}  
            }  
            |> PSeq.choose cycle  
            |> PSeq.length  
    



  • I wasn’t very happy with myself on this one. Part 1 wound up being simple enough, but part 2 took me for a loop. My disappointment was that I asked an AI for a hint, but instead it coded up a solution revolved around checking cycle dependency.

    I tried to at least redo it in a functional way, since I’m writing this in FSharp, but I ran into a bunch of hiccups around indexes and index tracking. That always costs me so much time. This took me forever and I’m near the bottom of the rankings haha.

    Overall, I wasn’t terribly happy with how I did on this one. Oh, I wound up switching all of the types to BigInteger because I was lost as to what was happening. It turned out to be indexes and orderings, but I thought that maybe something was getting truncated.

        /// Map from (prev, curr) pair to position  
        type PositionMap = Map<BigInteger * BigInteger, BigInteger * BigInteger>  
        let rec findCycle (pairToNextPair: PositionMap) startPair currentPair acc =  
            if currentPair = startPair && List.length acc > 0 then  
                Some (List.rev acc)  
            else  
                match Map.tryFind currentPair pairToNextPair with  
                | None -> None  
                | Some nextPair -> 
                    findCycle pairToNextPair startPair nextPair (snd currentPair :: acc)  
    
        let rec eni2' score (n:BigInteger) (exp:BigInteger) (m:BigInteger) (pairMap: PositionMap) (scores:BigInteger list) iter =  
            if iter > exp then scores |> List.rev |> List.skip (max 0 (List.length scores - 5)) |> toBigInt  
            else  
                let newScore = (score * n) % m  
                let key = (score, newScore)  
                
                match Map.tryFind key pairMap with  
                | Some _ -> 
                    match findCycle pairMap key key [] with  
                    | Some cycle ->  
                        let remaining = int64 (exp - iter)  
                        let cycleValues = cycle  
                        let cycleLength = List.length cycleValues |> int64  
                        let scoresLength = List.length scores |> int64  
                        let totalLength = scoresLength + 1L + remaining // scores + newScore + remaining  
                        
                        let needCount = min 5L totalLength  
                        let startPos = max 0L (totalLength - needCount)  
                        
                        let scoresReversed = List.rev scores  
                        
                        let final5 = 
                            [startPos..totalLength - 1L]  
                            |> List.map (fun pos ->  
                                if pos < scoresLength then  
                                    // Position is in scores (scores is reversed, so oldest is at end)  
                                    scoresReversed.[int pos]  
                                elif pos = scoresLength then  
                                    // Position is newScore  
                                    newScore  
                                else  
                                    let cycleOffset = pos - scoresLength  
                                    let cyclePos = cycleOffset % cycleLength  
                                    cycleValues.[int cyclePos]  
                            )  
                        
                        // final 5 comes out in reverse order  
                        final5 |> List.rev |> toBigInt  
                    | None -> 
                        eni2' newScore n exp m (Map.add key ((newScore, (newScore * n) % m)) pairMap) (newScore::scores) (iter + BigInteger 1)  
                | None ->  
                    let nextPair = (newScore, (newScore * n) % m)  
                    eni2' newScore n exp m (Map.add key nextPair pairMap) (newScore::scores) (iter +  BigInteger 1)  
    
        let eni2 (n) (exp) (m) = eni2' (BigInteger 1) n exp m Map.empty [] (BigInteger 1)  
    
        let part2 (input: IDictionary<string, BigInteger> array)=  
            input  
            |> Array.map (fun line ->  
                //printfn $"""running line {line.AsEnumerable() |> Seq.map(fun kv -> kv.Key + "=" + kv.Value.ToString()) |> fun x -> String.Join(", ", x)}"""  
                let a = eni2 line["A"] line["X"] line["M"]  
                let b = eni2 line["B"] line["Y"] line["M"]  
                let c = eni2 line["C"] line["Z"] line["M"]  
                let ret = a + b + c  
                //printfn $"found {ret}"  
                ret  
            ) |> Seq.max  
    
        let part2Answer = 
            File.ReadAllLines "Inputs/Q01_P02.txt"  
            |> part1Lines  
            |> part2  
    






  • I’m using it for some side projects. I used it as an assistant for setting up services in Kubernetes - also used it a lot for debugging and creating kubectl commands.

    another side project is to write a full web app in F# SAFE stack, which uses Fable to transpile to JavaScript and React, so I’m learning several things at once.

    At work I didn’t use it as much, but it got used to generate tests, since no one really cared enough about them. I also did some cool stuff where someone wrote a guide on how to migrate something from a V1 of a thing to a V2 of a thing, I hooked up MCP to link the doc, asked it to migrate one, and it did it perfectly.

    I used it a lot to generate Mongo queries, but they put that feature in MongoDB Compass.

    We used Claude Sonnet pretty much exclusively. for my side projects I often use Auto since Sonnet burns through the monthly budget pretty quickly. It definitely isn’t as good, but it tends to be favorable for template-y things, debugging why some strange thing is happening in F# or react.

    For the side projects, I find I’m using it less as I learn more. It’s good for getting over a quick hump if you have a sense of how things generally should be.

    I’ve considered the lakes I’ve burned because I didn’t copy paste those kubectl commands to a file.

    I prefer Sonnet. Anything less isn’t that great, which is one reason I think people hate it.

    I tend to use it for crufty things. And certain front end things. It’s been a long time since I’ve done web UI.