2025-12-29
15:14:06, atom feed.
Here is the commit log from last week's work.
2025-12-23
feat: introduce default allocator replacement for context
2025-12-26
feat: introduce "standard library" (sl) with ring buffer and test
2025-12-26
feat: add heap data structure and min-heap procedures to sl
2025-12-27
feat: separate min_heap out of heap impl; add max_heap; add tests
The main focus this week was pathfinding, but I was also up to some other peripheral things as well.
Firstly, we have the introduction of a default allocator replacement for the Jai
context. Jai passes around a special variable implicitly to each scope called
the context. I think I discussed this earlier, but in short, the context has
various useful properties on it such as the currently preferred logging function
and the preferred default and temporary allocators. In my case, I want to avoid
allocating using the default allocator. I also want to avoid allocating using
the temp allocator as much as possible, but I'm less concerned about this
because I clear its storage at the beginning of each frame. To catch usage of
the default allocator, I implemented my own allocator which just
assert(false, "[...]");s on any operation requested of it. I caught a few
issues with this, mostly String.join calls, that I fixed using
String.join(...,, allocator=temp);
Note the ,, which is an operator in Jai which allows you to modify context
properties at callsites for arbitrary functions. I would like to use my own
temporary allocators provided through the most basic of arenas, but for Jai
"standard library" things like this, it's easier to use Jai's temporary
allocator. I could always implement the allocator interface for my arena and
thus use my own backing memory pool, though. Probably a project for a later
time.
Toward pathfinding, I have a simple grid map with uniform cost to move between squares. I recalled the standard A* algorithm for pathfinding in such situations. It's been over 10 years since I've dealt with A*, though, so I needed a refresher. I came across Red Blob Games. This blog and the author's few others linked from it are a wealth of information on algorithms for games, particularly top-down, 2D ones such as mine. I highly recommend checking the site out if you're interested in such.
I thought I was going to use a queue, and a ring buffer would work well here,
so I implemented one. I followed a great tip from
Juho Snellman
on using only positive indicies (no forced wrap-around via %) and masking the
indicies only when you need to look into the backing storage. Clever and neat.
Now, it turns out I actually wanted a priority queue, so for that I decided to use a min heap. To my knowledge, Jai does not provide a min heap, so I implemented one of those as well. To brush up on that, I referenced the classic Introduction to Data Structures and Alrogithms book. I had learned from this in college as well. After re-reading a very small portion of this recently, I admit I cannot recommend it. It does many things well, but I find it overreaches with its advice in places and also (probably accidentally) misrepresents some concepts by overfitting descriptions on very narrow use cases in specific languages, for example by calling the heap a region of garbage-collected storage. Anyway, it did the job.
I ultimately implemented a heap (heap.jai) and then implemented the min-heap and
max-heap interfaces in respective files that both import heap.jai. I
reintroduced my "sl" concept from when I was playing with data structure
generation via the C preprocessor two or three weeks ago. I have a special file
in the sl module called test.jai which provides a main function and imports
all of the files in sl and tests their features. I have a build.jai file in sl
that builds a binary from test.jai. Building and running the tests is a manual
process, but I don't anticipate changing sl so frequently that I'll hurt for
any automation, except that one time when I will probably change it, introduce
a bug, and forget to run the tests haha.
I then got to implementing A*. The work is on a branch currently and will be the subject of this week's update.
I also started streaming livecoding (and some gaming) on Twitch, as noted in a previous post. The idea here is to maybe build even the smallest of audiences or at least presence in parallel with building the game instead of serializing the process. Presumably an audience takes just as long if not longer to build than the game itself, but what do I know--I'm totally new to this aspect!