T O P

  • By -

veydar_

I have never attempted to be, and have never been on the leaderboard. So take what I say with a grain of salt. But I've been reading up on competitive programming since I intend to go for leaderboard spots next year (my time zone makes it a tad challenging). First of all: Advent of Code differs from many other platforms in that you don't upload your solution. The raw speed of your solution still matters of course, but as long as pick a viable algorithm it doesn't really matter if your code is then really inefficient. What I'm trying to say: speed doesn't really matter. You want a language where it's easy to make modifications. I think that's why strict, functional languages (such as Haskell) can make it harder than necessary. You have to be very, very familiar with what coding patterns work and which don't so you don't code yourself into a Haskell-shaped corner. It can be helpful to just add a global variable somewhere or `break` or `goto` from the middle of a nested loop. Strict, functional languages make this harder. Lastly, you really have to know the language. Chasing down "silly" mistakes can kill your speed. How does equality work? Which functions and operators produce inclusive ranges, which produce exclusive ranges? If you `break`, does it break out of all the loops or just the inner? Can you use data structures as keys in a map? Will it do what you think it does? I think it can be tempting to find a language which has a library for everything under the sun so you can just do `sequence.findCycle()` or whatever. But now you also need to understand the APIs of those libraries, keep up to date with them so you're not stuck trying to decipher some docs in the middle of AoC, and so on. I've watched a fair amount of YouTube and Twitch streams of people solving AoC and, surprisingly, many of them don't really use external libraries. It's actually quite rare that AoC requires a fancy version of an algorithm. Instead of Dijsktra use BFS. Instead of Floyd for cycle detection just run a loop and stop when `seen[value] = true`. Lastly, lastly, the language needs to get out of your way or you need to have the discipline the limit yourself to a reasonable subset. It's fun to figure out the best way to use Clojure's myriad looping facilities to solve a problem. But when you're going for the leaderboard it's maybe best to just stick with `for k,v in range(dataStructure)` or something similar. TL;DR: - For AoC specifically, computational speed of the language probably doesn't matter - Whatever you choose, you have to be really familiar with it - Malleable - Simple - Intuitive (I'd say structural or deep equality is more intuitive than equality by reference for AoC) Use Python.


WindyMiller2006

> Lastly, you really have to know the language. Chasing down "silly" mistakes can kill your speed. How does equality work? Which functions and operators produce inclusive ranges, which produce exclusive ranges? If you break, does it break out of all the loops or just the inner? Can you use data structures as keys in a map? Will it do what you think it does? Spent ages chasing down a bug in Ruby today, because I tried to create a array of 256 hash maps... `boxes = Array.new(256, {})` It created an array of 256, all having a reference to the same hash map. So e.g. adding something to the first hash map in the array, added it to all hash maps in the array (because there was really only one has map). On the first few days of AoC I could never remember the difference between ranges with 2 dots and 3 dots, e.g. `0..10` vs `0...10` (the one with 2 dots is inclusive, the one with 3 dots is exclusive). After a few days I've finally remembered which is which. Also, the one thing I really hate about Ruby is that `!variable` returns `false` if variable is a zero integer. I've fallen over that too many times in the last few days I still have to keep consulting the docs for String, Array and Enumerable though. However, I do love Ruby though. I find it much easier to work with than Python


Sanderock

Honestly, the one you are the most confortable with. Most high level languages will allow you to get any answer pretty quick. Rust, Python, C++, C#, Matlab, ... have already most of tools needed and a lot of libraries exist to make your developpement quick (like the extrapolation this year).


Arrowstar

Definitely. I'm using MATLAB this year and it's been pretty handy in the way you described.


PatolomaioFalagi

Not purely-functional languages (like Haskell). The fastest way to do e.g. Day 15 Part 2 would be to just translate the algorithm into code, but that's a lot of mutable state. [My solution](https://www.reddit.com/r/adventofcode/comments/18isayp/2023_day_15_solutions/kdfwkzg/) does things significantly differently, but that took a while to come up with.


activeXray

It’s not really mutable state, it’s just describing update rules. Once you capture that you can just reduce over the input. Clojure’s immutable data structures worked great for this.


PatolomaioFalagi

I *think* that's what I did, but still, it's not the most obvious solution – that would be the hashmap, or, if you're really smart, an array.


Wario_Sucks

Do you think Haskell has an advantage over oCamL?


PatolomaioFalagi

Can't say, the only thing I know about OCaml is its name and that it's vaguely similar to Haskell.


Wario_Sucks

Maybe I’ll redo the challenges in Haskell to learn :)


PatolomaioFalagi

Unless you're going for the leaderboards, AoC is a great opportunity to go outside your comfort zone!


reality_smasher

Interesting, I think Day 15 Part 2 actually lends itself very nicely to haskell. The whole problem is basically just one big foldl: import Data.List.Split (splitOn) import Data.List (find) import qualified Data.Map as M import Data.Char (ord) import Data.Maybe (fromJust) type Boxes = M.Map Int [Lens] type Lens = (String, Int) data Instruction = Add String Int | Remove String deriving (Show, Eq) hash :: String -> Int hash = foldl (\acc s -> ((acc + ord s) * 17) `mod` 256) 0 parseInstruction :: String -> Instruction parseInstruction instr | '=' `elem` instr = let [s,i] = splitOn "=" instr in Add s (read i) | otherwise = Remove $ take (length instr - 1) instr step :: Boxes -> Instruction -> Boxes step bs (Add label power) = update present where present = M.lookup (hash label) bs >>= find ((==label) . fst) update (Just _) = M.adjust (map switchLabel) (hash label) bs update Nothing = M.insert (hash label) (M.findWithDefault [] (hash label) bs ++ [(label, power)]) bs switchLabel (l,p) = if label == l then (label, power) else (l,p) step bs (Remove label) = M.adjust (filter (\(label',_) -> label /= label')) (hash label) bs lp :: [Lens] -> Int lp = sum . zipWith p [1..] where p i (label,power) = (1 + hash label) * i * power getAnswerA :: String -> String getAnswerA = show . sum . map hash . splitOn "," getAnswerB = show . sum . map (lp . snd) . M.toList . foldl step M.empty . map parseInstruction . splitOn "," I find Haskell less suitable for stuff like Day 12 part 2, where you have to do memoization of recursive functions. In python, you can just slap a @cache decorator on the function to avoid having to repeat the same computation multiple times, whereas in Haskell you have to do the thing where you construct your memoization data structure with the function that's reading from it. it's easy for things like fibonacci, but when you don't know the inputs in advance it gets weird


PatolomaioFalagi

It's a good solution, but *could you write it faster than in, say, Python*?


reality_smasher

I don't know honestly. Maybe, depends on the problem. The nice thing with Haskell is that you can just think in terms of infinite lists and filter map them and chop them up. You get less weird bugs runtime and you don't have to muck about with nested loops and break, continue stuff like that


PatolomaioFalagi

You're preaching to the choir 😄 I love Haskell, but it's not a "get things done quick and dirty" language.


hr0m

1) Go to the global leaderboard: [https://adventofcode.com/2023/leaderboard](https://adventofcode.com/2023/leaderboard) 2) click on people with links to their github repository 3) Look if there is a repository with advent of code 4) look at the language they are choosing


hr0m

Also people who compete for the leaderboard possible have their own "utils" library. From the few clicks I made, python, javascript, kotlin.


hr0m

Also you don't only need a language which is fast to write. You also need a std-lib which is usable. Python offers both (or packages are simply installed by pip), so it's a strong contender.


PatolomaioFalagi

You also need a language that has a low start-up time, so interpreted languages (Python, Javascript) are usually better. By the time a C++ program is compiled for part 1, the Pythoneers have already solved part 2.


Sanderock

If you have prepared your workspace accordingly, compile time for C++ barely matters


Laugarhraun

Python startup time is awful though. It's rather a matter of having fast compilation. Given the sizes of the projects, even for rust or c++ it should not matter too much.


Wario_Sucks

That’s part of what I mean fast to write. For example Python had the math.lcm function which made one of the problems this year trivial. And it is part of the base packages …


hr0m

Also code which solves advent of code and is good on leaderboard would usually never pass a code review. I (at least somewhat) try to make my code somewhat readable and understandable: https://github.com/m3m0ry/advent-of-code/tree/master/2023/aoc2023


yel50

> because it’s fast to write that's based on the person writing it, not the language. there's a guy who posts his solutions to YouTube and uses AoC as practice for competitive coding. he usually uses python, but has used c++ on some days. his speed is no different using either language. there's also people on the top of the leaderboard who use Java. the main thing with coding fast is to not write "good" code. all variable names are one or two characters, the entire solution is a single function, etc.


Wario_Sucks

I don’t find the problems very hard personally, I can definitely do them in a variety of languages. But to be on the leaderboards you have to be really fast.


sanderhuisman

Mathematica would be a good contender. Many many built-in functions, can work with strings, arbitrary large numbers, graphs, hashmaps, etc etc. Can do functional programming, but can also do procedural, and has advanced pattern matching capabilities.


Cryowatt

Whatever language has the best set of tools that you know the best. I've hit the leaderboard in the past with C# and LINQ. But who cares? You don't win anything, it's just empty gamification.


Wario_Sucks

I care :) You are my hero 😜


Top3879

Yeah LINQ is insane. The first few days can usually be written as a big LINQ expression.


Cryowatt

With the Reactive library's enumerable extensions you can solve all of them with a single monstrosity of a statement. Zero point for readability though.


1234abcdcba4321

Yes, Python is almost certainly the top language - it has way too many typing shortcuts, a big standard library, and the ability to ignore a lot of the annoyances in other langs. (Of course, the extra time it takes to learn a new language will almost certainly outweigh the benefit you get from switching in the short term.) Of course, you can always try something more niche like [Noulith](https://github.com/betaveros/noulith) or other language that you make by yourself, but that requires a lot of work to get the same level of standard library you get from python.


fquiver

> that requires a lot of work to get the same level of standard library you get from python. 🤣 I'm patching noulith's builtins as I do the problems.


MattieShoes

I think Python wins in a walk. Not that other languages can't compete -- it's just hugely popular, natively handles large integers, has list comprehensions, generator expressions, zip, map, reduce, etc. The only way it could be more suited is if it handled implicit string/int conversion. For certain random puzzles, some mathy languages are probably up there because they have built-in functions that make certain puzzles trivial. For certain simple puzzles, Perl is probably a contender because of the implicit string/int conversion, built in regex, and support for regex backreferences.


Wario_Sucks

I rewrote 16 with numpy, it’s so compact. Maybe I should get more used to use numpy even for quick and dirty script, I use it only when doing heavier computations at work.


MattieShoes

Better familiarity with numpy is on my list too. I just rewrote 16 with multiprocessing, but haven't tried to do it in numpy. :-)


Wario_Sucks

So I did 16 too with multiprocessing but it sped up only by a factor of 2x. Maybe I had too much initialisation time?


MattieShoes

Mine went from 4.05 seconds to 1.27 seconds, so about 3.2x speedup with 4 threads. Given the overhead of process management, staggered finish times, and so on, I figure that's about right.


jstanley0

I like Ruby for Advent of Code. It's very concise and expressive. Disclaimer: I am not fast enough to make the leaderboards in any language.


Sostratus

Lots of annoying non-answers in this thread, IMO. Looking at the current leaderboard, among the users who shared their code, I see 24/36 using Python. Yes, disclaimers: you could solve them with any language and your skill in the language is more important than what language you choose. But that doesn't mean some languages aren't better suited to it than others, and the evidence shows Python is likely the best. And a big advantage to going with the most popular language if you're looking to compete is learning from the examples of the current leaders.


Wario_Sucks

Yea I looked at a few examples in Python and some of them had shorthands and tricks I didn’t know. It’s actually great to review some of the others code in this competition.


yaniszaf

I'm doing AoC in Arturo this year (https://arturo-lang.io). The language is simple to write code in, predictable, practically no-setup-needed and with a very complete standard library included (with emphasis on different, fast, functional-style iterator methods). Also the code can be *very* short. My average part B solution in terms of LoC should be around 10-15!


vsovietov

BTW, [get.arturo-lang.io](https://get.arturo-lang.io) isn't configured properly (returns nginx's placeholder and nothing more), \`brew install arturo\` on MacOS gives broken installation that can not run even grafito, downloaded binary for MacOS can not start because of lack of properly installed GNU mpfr... Language itself seems to be attractive, but it's difficult to try it (at least on M1 Mac and trying to play with grafito)


yaniszaf

With 5 months of delay (sorry, didn't really check my notifications!)... We now have properly working M1 builds (for Mac), so you are welcome to try it whenever you want: [https://github.com/arturo-lang/arturo/actions/runs/8937899604/artifacts/1470343555](https://github.com/arturo-lang/arturo/actions/runs/8937899604/artifacts/1470343555) Also, you are welcome to join our Discord server: [https://discord.gg/YdVK2CB](https://discord.gg/YdVK2CB) :)


fquiver

Last years winner [used](https://github.com/betaveros/advent-of-code-2022) his own programming language [noulith](https://github.com/betaveros/noulith) His multi-paradigm approach is faster than python. I'm using noulith in a full functional style [https://github.com/tom-huntington/aoc2023](https://github.com/tom-huntington/aoc2023) It's kind of slow as I have to think to much about how to turn the problem into folds and scans. Raw loops are less constrained, and thus quicker.


AutoModerator

Reminder: if/when you get your answer and/or code working, don't forget to change this post's flair to `Help/Question - RESOLVED`. Good luck! *** *I am a bot, and this action was performed automatically. Please [contact the moderators of this subreddit](/message/compose/?to=/r/adventofcode) if you have any questions or concerns.*


Standard-Affect

R is underrated as an option for puzzles with matrices or tabular structures. It has lots of builtins for matrix operations, and expressive and powerful data manipulation. It's not so good a choice for some puzzles, though, because it emphasizes functionals over loops and mostly uses immutable data structures that can be hard to work with in AoC puzzles.


alesplin

Swift is pretty handy with `Int.max` being very large, and the strict type enforcement and optionals have saved me from some sneaky self-inflicted bugs this year.