Files
coding-challenges/everybody-codes/2025/EveryBodyCodes2025/EveryBodyCodes_WrongOne/QuestOne.fs

143 lines
5.0 KiB
Forth

module EveryBodyCodes2025.QuestOne
open System
open System.Collections.Generic
open System.IO
open System.Linq
open System.Numerics
open System.Threading.Tasks
let eni (n:BigInteger) (exp:BigInteger) (m:BigInteger) =
let mutable remainders = []
let mutable score = BigInteger 1
for _ in (BigInteger 1)..exp do
score <- (score * n) % m
remainders <- score::remainders
List.rev remainders // Reverse to get correct order (oldest first)
// let test1 = eni 2 4 5 |> fun l -> String.Join("", l) |> int64
// let test2 = eni 3 5 16 |> fun l -> String.Join("", l) |> int64
let part1Lines (input:String array) =
input |> Array.map (fun line ->
line.Split(" ") |> Array.map(fun segment ->
let parts = segment.Split("=")
let alias = parts[0]
let num = parts[1] |> BigInteger.Parse
(alias, num)
)
|> dict
)
let toBigInt (list:'a list) = String.Join("", list) |> BigInteger.Parse
let part1 (input: IDictionary<string, BigInteger> array)=
input
|> Seq.map (fun line ->
let a = eni line["A"] line["X"] line["M"] |> toBigInt
let b = eni line["B"] line["Y"] line["M"] |> toBigInt
let c = eni line["C"] line["Z"] line["M"] |> toBigInt
a + b + c
) |> Seq.max
|> fun x ->
printfn $"{x}"
x
let part1Answer =
File.ReadAllLines "Inputs/Q01_P01.txt"
|> part1Lines
|> part1
/// 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.mapi (fun i 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 test2 =
let a = eni2 5 6 15
let b = eni2 9 16 15
let c = eni2 7 18 15
let r = a + b + c
printfn $"{r}"
r
let part2Answer =
File.ReadAllLines "Inputs/Q01_P02.txt"
|> part1Lines
|> part2
|> fun x ->
printfn $"part2 {x}"
x
let part2Answer' file =
File.ReadAllLines file
|> part1Lines
|> part2
|> fun x ->
printfn $"part2 {x}"
x