Drawing ASCII Art to Test a Physics System
1 | // ____ __ |
Generating my own ASCII art in programming projects is a great way to solve certain hard problems. Diagrams made from PNGs with some kind of rendered documentation is great, but it has a high barrier to entry. Plus, this kind of documentation does not live with the code, which makes it easy to miss and forget about. I have started a series of posts detailing various strategies on how I draw with ASCII.
Testing a Physics System
Physics systems are lot of fun to play around with. However, they end up being fairly error prone, really finnicky with various inputs, and hard to reproduce issues. I was working on my sphere physics system, and noticed that I was getting lots of different errors with points shooting through spheres, but no way to debug the system. I had thousands of individual points, and the simulation was running at 60 frames per second. The issue happened every couple of seconds where a point would zoom across the screen. Now, how to catch that?
I had some suspicions on what was going on, but didn’t have a great way to reproduce them. The numbers that make up a physics system are so abstract as to be almost worthless. I wanted to build something visual. However, setting up an image testing scheme is finnicky at best, and slight differences in renders can easily lead to false negatives.
ASCII to the rescue
Text-only output is great to test against. It can be checked right into the codebase. It can be commented on and included exactly where you are using it. First off, for the physics system. We need to draw points in motion. In order to do this, we need a velocity vector, and then a bit of math to convert that into a direction.
1 | function getArrow(vec: Vec2): string { |
It’s not a typical rendering engine, but it will do. When I first started writing these tests, I kept it pretty simple. But, as I added more test cases I found I needed to encapsulate this logic better. Enter the Stage class.
1 | class Stage { |
The full source code for the Stage is available, but one example of drawing a sphere will hopefully suffice to give a general impression of the strategy to render to text.
1 | class Sphere { |
I will reproduce an entire test case below (written using Jest), as I think it shows off the problem and solution pretty well. Feel free to skim the code itself, and look at the text diagrams. I amended the original code with more comments to explain what is going on.
1 | describe("collisions between point and sphere", function() { |
This was the first test I wrote, and it felt like writing something that targeted the 2d canvas. I could set up the situation visually, and step through the results to see the behavior. Finally, let’s find the bug that I mentioned earlier.
1 | it("handles points that are inside of spheres on their way in", function() { |
Jest was quite nice in handling these type of tests, and provided a fairly easy to read diff. I could also re-generate the visuals directly in the code itself using the inline snapshot feature. This next diff shows an example of what a test with an error could look like.
1 | - Snapshot - 2 |
This was a personal visualization project, so I was enjoying exploring the tests and physics system as much as I wanted to see the outcome. Rendering to text made it easy to reproduce a visual system that was made up of very abstract, and magical numbers that would normally be hard to write a test for. This ASCII art trick is fun for a physics system, but it works equally well for other visual data structures that are quite common in computer programming. I’ve definitely used it to a pretty nice effect in the Firefox Profiler.
Finally, if you enjoyed this article, then why not take a break and watch my finished physics simulation.
