Minimum Viable Dice Wars

Minimum Viable Dice Wars

Anybody else miss flash games?

Playing those games is one of my earliest and fondest memories on the internet. I remember making the trip to my elementary school’s computer lab where we were allowed to visit coolmath4kids.com (which looks a lot different decades later) because the games were supposed to be educational.

Despite the best efforts of our teacher to police it, we all snuck over to a section of the website known as “Spike’s Game Zone”. This was where the mindlessly fun games were.

As I grew up my tastes became more sophisticated. One flash game that I found very addicting as a kid was simply called “Dice Wars”. It’s like the board game “Risk” in a lot of ways, but with a little more luck involved. If you want to play the original, you can check it out here.

Minimum Viable Dice Wars

I decided it would be a fun project to try to build my own version of Dice Wars. I’m calling it, “Minimum Viable Dice Wars”, as it’s a bit different and not nearly as polished as the original. However, it is playable and has most of the same major features.

You can play my version of Dice Wars by clicking this link.

And you can check out the source code by clicking this link.


One thing I always get self-conscious about when I share more ambitious side projects with you all is the code quality. I make these games in bits of my spare time. As somebody who builds software professionally, I’m never quite satisfied with the end result.

Most of the algorithms in this project are brute force approaches, and there are plenty of performance optimizations that I could make. However, if I held off on sharing these projects until they were perfect I’m not sure I’d ever publish anything.

Instead of walking through all of the code and explaining it line by line, as I have done in some of my previous tutorials, I’ll be focusing on the approaches I took while implementing the more interesting sections.

I took a similar approach when discussing the crossword puzzle generator. It’s another project with a bit higher level of complexity, and that approach seemed to work well for demonstrating concepts without getting bogged down in the details.

Of course, feel free to ask questions about any particulars you find interesting or confusing.

Game Board Generation

I’m pretty sure the original version of Dice Wars uses some kind of tree or graph data structure for representing the game board. It really intrigued me how the original developers built it and integrated it with the graphics.

Going with the “minimum viable” theme, however, I decided to go with a 2D array. It gives the game a bit of a unique feel too, in my opinion.

The basic approach I took for generating random boards looks like this:

  1. Generate an empty square board of fixed size using a 2D array.
  2. Pick a random, but reasonable, number of tiles to make empty. When choosing the random placement of the tiles, don’t let these empty tiles be on the “inner ring” of the board. This will help us avoid creating hanging tiles. A hanging tile is one that doesn’t connect to any other tile and thus can never be captured.
  3. Randomly assign the same amount of dice to each team on the available tiles, and make sure they are distributed in varying amounts.
  4. Clean up any hanging tiles. The code I wrote for this doesn’t cover all cases, but I think it is sufficient given the additional precautions taken in step 2 above.
Minimum Viable Dice Wars - Inner Ring of board

Find Connected Tiles

One key element of Dice Wars is that you get bonus dice based on your largest group of connected tiles. This proved to be tricky, and I’ll admit I used Stack Overflow for a bit of initial direction. Once I understood the basic idea I was able to modify it to fit my use case.

The general idea is to loop through all the tiles on the board and use recursion to check each tile’s connected tiles to see if they are owned by the same team….and then do the same thing for each of those connected tiles…and so on.

Once all the branching tiles have been checked and the base case has been reached the function returns the connected tile count along with an array of the connected tiles.

I started by creating an array of the neighboring tiles. I represented each tile as an object containing coordinates, a name designating the directional relationship to the original tile, and whether it was a valid direction given its position on the game board.

Get neighboring tiles

The result of this function helps to simplify the recursive code. It allowed me to loop through the array and call the same function repeatedly instead of checking multiple if statements like shown in the Stack Overflow example.

Find number of connected tiles.

I added the tile to an array and incremented the total count whenever it was valid, belonged to the same team, and hadn’t already been checked.

Find number of connected tiles in direction

Artificial Intelligence

It took a bit of tweaking, but it turns out a few simple rules are all it takes to create a serviceable AI for a Minimum Viable Dice Wars. There are two main things the AI does. The AI will attack from a tile if:

  1. It is adjacent to a weaker tile owned by an opposing team.
  2. It has the maximum number of dice and is adjacent to a tile owned by an opposing team that also has the maximum number of dice.
Artificial Intelligence code for minimum viable Dice Wars

There are many ideas for improvement I haven’t implemented yet, including ranking the attack options, focusing attacks on the team in the lead, and attacking again from a conquered tile after a successful attack.

It seemed pretty fun to play against though, so I haven’t bothered with it yet.

Conclusion

I had a lot of fun making this minimum viable version of Dice Wars. I hope you enjoyed following along. Subscribe to my blog or follow me on Twitter if you’re interested in seeing more projects like these.