Day 13: Claw Contraption

Megathread guidelines

  • Keep top level comments as only solutions, if you want to say something other than a solution put it in a new post. (replies to comments can be whatever)
  • You can send code in code blocks by using three backticks, the code, and then three backticks or use something such as https://topaz.github.io/paste/ if you prefer sending it through a URL

FAQ

  • RagingHungryPanda@lemm.ee
    link
    fedilink
    arrow-up
    1
    ·
    4 days ago

    I had to borrow some of y’alls code to finish part 2. My approach and all the attempts I did at trying to get the slopes of lines and such couldn’t get it high enough.

    I thought to move from the prize along it’s furthest away axis until I got to the intersection of the slope of the two buttons.

    I thought that maybe that wasn’t the cheapest way, so I fiddled around with the order of button A and B, but still couldn’t get it high enough.

    It looks like this group was mostly doing the cross product of the prize to the two buttons. I’m too dumb to realize how that would work. I thought you’d want to move along the furthest away axis first, but maybe it doesn’t matter.

    If anyone can see if I did anything obviously wrong, I’d appreciate it. I normally don’t like to take code without fixing whatever it is I was doing since it always bites me in the butt later, but here I am.

    F#

    expand for source
    let getButtonCounts (buttonA: Button) (buttonB: Button) buttonACost buttonBCost (prize:Prize) =
        // my way of trying to solve by moving the greatest axis first doesn't work for part 2.
        // everyone else seems to be using the slope between the two buttons and applying the cost
        // to a part. I don't see how it works but fuck it.
        // I had to add the `abs` calls to a and b to the borrow code, so who knows wtf. I'm done.
        let cpAB = crossProduct buttonA buttonB
        if cpAB = 0 then None
        else
            let detA = crossProduct prize buttonB
            let detB = crossProduct prize buttonA
            let struct(a, rem_a) = Int64.DivRem(detA, cpAB)
            let struct(b, rem_b) = Int64.DivRem(detB, cpAB)
            if (rem_a <> 0 || rem_b <> 0) then None
            else (abs(a) * (int64 buttonACost) + abs(b)) |> Some
        
        
        // here's where my code was. It came up short on part 2
        let (majorAxis:Point2<int64> -> int64), (minorAxis:Point2<int64> -> int64) = if prize.X > prize.Y then _.X, _.Y else _.Y,_.X
        let firstButton,firstCost, secondButton,secondCost =
            if majorAxis buttonA = majorAxis buttonB then (buttonB, buttonBCost, buttonA, buttonACost)
            else if majorAxis buttonA > majorAxis buttonB then (buttonA,buttonACost, buttonB,buttonBCost)
            else (buttonB, buttonBCost, buttonA, buttonACost)
        
        let origin:Point2<int64> = {X = 0; Y = 0}
        let toSlope button  = Segment.Slope.findL {Start = origin; End = button}
        
        let majorLine = (toSlope firstButton) |> fun s -> {Point = prize; Slope = s }
        let minorLine = (toSlope secondButton) |> fun s -> {Point = origin; Slope = s}
        
        let minorOffset = {Point = secondButton; Slope = minorLine.Slope }
        let intersection = Line.intersection majorLine minorOffset
                           |> Option.filter intersectsOnWholeNumber
                           // |> Option.filter (fun i -> i.X <= (float prize.X) && i.Y <= (float prize.Y)) // is in bounds
                           |> Option.map(fun p ->
                               let pp:Point2<int64> = {X = p.X |> round |> int64; Y = p.Y |> round |> int64}
                               pp)
                           // comparing by slopes can intersect outside of the bounds
                           // of the prize, which is not compatible
        
        match intersection with
        | None -> None
        | Some i -> 
            // steps to move to intersection
            let firstMovement =  (majorAxis prize - majorAxis i) / (majorAxis firstButton)
            // steps to move to 0
            let secondMovement = (minorAxis i) / (minorAxis secondButton)
            
            let cost = firstMovement * (int64 firstCost) + secondMovement * (int64 secondCost)
            Some cost