Virus generation mostly complete

Today I pushed some engine changes to rendering and got a full final first draft done of the virus generation code. Not quite as much as I wanted to get done, but better than a kick in the pants.

The engine now sports rendering of stroked shapes instead of just filled shapes, which I have wanted to cram in there for a while but never really had any need. This is now used in concert with the debug property on Segment, which is a boolean value; when it’s set to true, the current bounding box of the Segment is rendered prior to whatever the contents are.

As you can see in the screenshot below, I have this turned on for the empty segment in the segment selector and for all of the segments in the top three rows of the bottle, which should never have viruses inserted into them because of the minimum headroom needed to solve levels.

The big thing in the new version though is virus generation. This is more or less the version from the original NES version of Dr. Mario as outlined in this wiki post. This is not a one to one mapping, however.

The general gist of the algorithm used is:

  • There is a set maximum height in the bottle that the viruses can populate, which varies based on what level the game is on.
  • The position in the bottle is initially randomly generated, but will get bumped if the place selected contains a virus already.
  • The color of the inserted viruses goes in a set order, but every fourth virus is randomly selected.
  • On insertion, a check is done on the segments 2 positions away from the selected location in every direction; if all colors are represented, the virus cannot be placed here because it would put two of the same virus too close together. For other combinations we insert a virus color that doesn’t already exist.
  • It is possible for a pass of the insertion algorithm to fail to insert a virus if the position selected is inadequate.
Sample Virus setup

Sample Virus setup for level 20 (84 viruses)

A couple of parts of this as described confuse me. The biggest confusion is in that last one; the way the algorithm is described, whenever the situation arises that a virus cannot be inserted due to the proximity neighbors having all colors represented, we just scan one more virus position to the right and continue on. No check is done to ensure that a virus is not being clobbered over, which in my testing happens all the time.

This would lead to short virus counts in the level, since the function is just invoked until it eventually manages to insert something enough times, and when this happens it would overwrite an existing virus but still say it inserted one. The way I have implemented this, if the position is invalid it just bails out and returns back without inserting anything.

The other thing is that it seems to want to generate a virus for rows up to 16, which would fill the bottle right up, even though in practice it always leaves the three required spaces on the top. I’ve just gone ahead and constrained that.

I did some automated testing and never had it generate a puzzle with an initial match, so I’m considering this good enough for now, but I want to tweak it a bit more. I think perhaps the non uniformity of the random numbers JavaScript is spitting out might be skewing things, but that’s just a guess.

In any case, progress!