Combat is really complicated. I realize some people might say, “No, combat is easy. It is just programming.” But programming combat is a tough, thorny problem. Thankfully, once our brains get accustomed to Magic, combat is pretty simple in real life. That creature dies, and that ability triggers, no biggie. But once you test for everything like bouncing creatures after damage is assigned, calculate trample damage, first and double strike, and abilities that trigger when they damage another creature or player, the code starts to look a little messy.
Thankfully I think all of those mentioned features are working. I also figured since combat is essentially difficult I should do a little bit of automatic testing, like around 30 tests, which would test 90% of all situations. I am working on version 2.0, which is still under development and has a long way to go.
Like all great journeys it was a hard one. First, I wrote 200 lines which I thought totally worked and named it “Combat1”. I had an idea that Combat2 and 3 might be needed, and I was right. Combat1 worked in my head but not in reality. I am not sure if anyone else has had this problem. In your head it seems perfect, but then that piece of code doesn’t work correctly. Oh the joys of programming. That would make a good book title.
OK, so I quickly program Combat2 that has similarities to Combat1 but actually works as promised. I’m happy. It passes all of the tests and life is good. Unfortunately the code is rather messy and a little hard to follow. And it is very likely that there are a few really nasty errors hidden in the messy part. So I take out a bunch of variables and put them into a different class called CombatMap. So Combat3 uses CombatMap, and although the combined new code is longer than Combat2, the logic is easier to follow.
Oops, another snafu. Verifying creatures in play is messy and complicated. This is an artificial step that the computer has to do in order to make combat work correctly. This step of verifying creatures that are in play is taken for granted because we have trained our brains to work that way. So give a big welcome to Combat4, which moved all of the “verify creatures in play” code to CombatMap. It takes a couple of tries to make it work with the tests, thankfully they are automated, but it works nicely.
The trick was removing Card objects that were both keys in a Map as well as the data values. The map key was the attackers, and the data was the blockers. Thankfully it seems to be working and hopefully I don’t have to touch it with a ten-foot stick for many months.
Protection should work because Combat4 uses the Magic Engine to do damage. Combat4 deals damage by “magicEngine.damage(Card to, int damage, Card damageFrom)” So the method can check for protection and all that jazz. I spent probably 10-15 hours on Combat 1-4. I pseudocoded parts of it, but the devil is in the details, so I ended up writing the whole thing and then testing it.