Quest 1: Whispers in the Shell
- 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
Link to participate: https://everybody.codes/
my boring python solution:
from pathlib import Path def main(): input = Path('input.txt').read_text().split('\n') names = input[0].split(',') instructions = input[-1].split(',') print(names,instructions) index = 0 for instruction in instructions: dir = instruction[0] number = int(instruction[1:]) if dir == 'L': index -= number if index < 0: index = 0 else: index += number if index > len(names) - 1: index = len(names) - 1 print(names[index]) index = 0 for instruction in instructions: dir = instruction[0] number = int(instruction[1:]) if dir == 'L': index -= number else: index += number print(names[index%(len(names))]) indexes = list(range(len(names))) for instruction in instructions: dir = instruction[0] number = (int(instruction[1:]) if dir == 'R' else -int(instruction[1:])) % len(names) indexes[0], indexes[number] = indexes[number], indexes[0] print(names[indexes[0]]) if __name__ == "__main__": main()I probably should read all 3 files though. I’ll hone it out later.
So far I really like the difficulty level of EC, compared to AOC.
Quest 1 is pretty straightforward:- part 1: add offsets to index then clamp it between
0..limite.g.min(limit, max(0, index)) - part 2: add offsets and then modulo to figure out last index
- part 3: swap first element with element at
index mod names.lenuntil done =)
My solution in Nim:
proc parseInput(input: string): tuple[names: seq[string], values: seq[int]] = let lines = input.splitLines() result.names = lines[0].split(',') let values = lines[2].multiReplace({"R":"","L":"-"}) for num in values.split(','): result.values.add parseInt(num) proc solve_part1*(input: string): Solution = let (names, values) = parseInput(input) var pos = 0 for value in values: pos = min(names.high, max(0, pos + value)) result := names[pos] proc solve_part2*(input: string): Solution = let (names, values) = parseInput(input) let pos = values.sum() result := names[pos.euclMod(names.len)] proc solve_part3*(input: string): Solution = var (names, values) = parseInput(input) for value in values: swap(names[0], names[euclMod(value, names.len)]) result := names[0]Full solution at Codeberg: solution.nim
- part 1: add offsets to index then clamp it between
Ooh, challenges! Here we go!
I haven’t really written any Haskell since last year’s AoC, and boy am I rusty.
import Control.Monad import Data.List import Data.List.Split import Data.Vector qualified as V readInput s = let [names, _, moves] = splitOn "," <$> lines s in (names, map readMove moves) where readMove (d : s) = let n = read s :: Int in case d of 'L' -> -n 'R' -> n addWith f = (f .) . (+) part1 names moves = names !! foldl' (addWith $ clamp (length names)) 0 moves where clamp n x | x < 0 = 0 | x >= n = n - 1 | otherwise = x part2 names moves = names !! (sum moves `mod` length names) part3 names moves = V.head . foldl' exchange (V.fromList names) $ map (`mod` length names) moves where exchange v k = v V.// [(0, v V.! k), (k, V.head v)] main = forM_ [ ("everybody_codes_e2025_q01_p1.txt", part1), ("everybody_codes_e2025_q01_p2.txt", part2), ("everybody_codes_e2025_q01_p3.txt", part3) ] $ \(input, solve) -> readFile input >>= putStrLn . uncurry solve . readInputWhat do the
.s mean inaddWith f = (f .) . (+)?.means function composition in Haskell.(f .) . (+)is just an obscure way to write\x y -> f (x + y). It’s not recommended to use this point-free style in production code, but it is sometimes fun to experiment with for challenges like this.
I coded this along with my girlfriend who’s learning python, but not motivated to share her solution. The program reads from stdin, because I usually invoke it like so:
runhaskell Main.hs < inputorrunhaskell Main.hs < example. I think this is quite handy because I don’t have to change the source code to check the example input again.I struggled with Part 3, where I suddenly forgot I could’ve simply used
mod, which I ended up doing anyway. I immediately recognized that Part 3 needs Mutable Arrays if I care to avoid Index hell, which is not what I wanted to with Haskell but oh well.{-# OPTIONS_GHC -Wall #-} {-# LANGUAGE PatternSynonyms #-} module Main (main) where import qualified Data.Text as Text import qualified Data.Text.IO as TextIO import Control.Monad ((<$!>), forM_) import Data.Text (Text, pattern (:<)) import qualified Data.List as List import qualified Data.Array.MArray as MutableArray import Control.Monad.ST (runST, ST) import Data.Array.ST (STArray) commaSepLine :: IO [Text.Text] commaSepLine = Text.split (== ',') <$!> TextIO.getLine readInstruction :: Text -> Int readInstruction ('R' :< n) = read . Text.unpack $ n readInstruction ('L' :< n) = negate . read . Text.unpack $ n readInstruction _ = undefined myName :: (Foldable t, Ord b, Enum b, Num b) => b -> t b -> b myName maxPosition = List.foldl' (\ pos offset -> min (pred maxPosition) . max 0 $ pos + offset) 0 parentName1 :: [Int] -> Int parentName1 = List.sum newSTArray :: [e] -> ST s (STArray s Int e) newSTArray xs = MutableArray.newListArray (0, length xs - 1) xs swap :: (MutableArray.MArray a e m, MutableArray.Ix i) => a i e -> i -> i -> m () swap array i0 i1 = do e0 <- MutableArray.readArray array i0 e1 <- MutableArray.readArray array i1 MutableArray.writeArray array i0 e1 MutableArray.writeArray array i1 e0 parentName2 :: [Text] -> [Int] -> Text parentName2 nameList instructions = runST $ do names <- newSTArray nameList arrayLength <- succ . snd <$> MutableArray.getBounds names forM_ instructions $ \ offset -> do let arrayOffset = offset `mod` arrayLength swap names 0 arrayOffset MutableArray.readArray names 0 main :: IO () main = do names <- commaSepLine _ <- TextIO.getLine instructions <- fmap readInstruction <$> commaSepLine let namesLength = length names print $ names !! myName namesLength instructions print . (names !!) . (`mod` namesLength) $ parentName1 instructions print $ parentName2 names instructionsI 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 |> part2Hmmm, I am certain I did the wrong one? I did quest 1, I’m pretty sure
I’m very curious about F# since I’ve never used it or seen it anywhere before but I’m afraid I’m too tired to read it right now. Thank you for posting, I hope I’ll remember to come back tomorrow.



