Building Battleship on Algorand

Victor Shahbazian
7 min readJul 10, 2021

The app I built for the Universities Unchained Algorand Bounty Hack was Battleship. More specifically, I made a simplified version of Battleship in which each player only has two turns: one to place their ship and another to guess where they think their opponent placed their ship. This was done to intentionally reduce the complexity of the smart contract. Admittedly, the contract I wrote doesn’t differ much from the Rock, Paper, Scissors application I wrote in the Reach tutorial. This ended up being the key reason why I was able to complete a functional application on time. Now that I’ve built the application all the way through, I’m getting ready to start building more complicated applications in Reach.

Getting back on track with Battleship, the key differentiator between this application and the Rock, Paper, Scissors game built in the Reach tutorial is the use of arrays. I‘ve chosen to represent an array with a 3x3 grid, mapping each entry in the array to a square on the grid. The design was pretty straightforward; I just used an array of unsigned integers instead of an unsigned integer. Just like that the application was ready. Well…not quite.

The array presented challenges from within the contract itself. In order to verify the winner, the selected ship locations from one player need to be compared to the guesses made by the other player. Typically, the answer to this is to create a loop and iterate over each array entry, comparing the entries for matching values. So, I set out to create a while loop to run this comparison. All looked to be well. The automated .mjs testing file worked appropriately returning the values that were expected from the randomized test data I generated. It wasn’t until I implemented the frontend of the application and actually ran the comparison from the Algorand devnet did I find a major flaw in how I had implemented the comparison.

[ EMBED/INSERT YOUTUBE LINK: https://youtu.be/WpDBklKZwbc ]

The first error that popped up was in the console of the Deployer. I kept seeing a 400 post error being spit out on the console over and over again. At first, I didn’t know what this was, but then I later realized that there were nine error messages being logged. Finally, the light bulb in my head turned on and I realized that the error was coming from the while loop.

After requesting some help from the Reach Discord channel, I was informed that this was due to a race condition presented when the two players tried to be the first to call the publish method from within the loop. I was also informed that the error can generally be disregarded, the post is going to fail and that was the end of it. Well, I wasn’t okay with the error message and came up with a duct tape solution to the problem by making it so that the Attacher was the only participant calling the publish method. This did indeed fix the problem, I no longer saw the error messages on the Deployers end.

But that wasn’t the end of it…

You see, publishing and committing nine times is very very slow. At the time of writing this article, there is really no getting around this for now. This made the game borderline unplayable. I imagined that not many people would sit there for five minutes waiting for the contract to finish verifying the results. To avoid this excessively long waiting time, I decided not to use the while loop. Instead, I compared the arrays manually. This added many new lines of code to the contract which make it look much more bloated than when using the while loop. However, the performance increase was substantial and was totally worth the bloat. Instead of taking about five minutes to verify, it instead takes roughly 30 seconds.

On Day One

On the first day of the Bounty Hack, I was eager to get started. There was so much I wanted to do and just one month to do it. I also wanted to get the application to a playable state (if not finish it entirely). I didn’t want this to become just another abandoned side project. Knowing I’d be paid for completing my application (and not just being chosen as the winner) allowed me to focus on completing the most important parts of the app before moving onto the nice-to-have features.

Intent

I also viewed the hackathon as a chance to get better acquainted with the more recent features of React, (e.g. hooks such as useEffect and useContext). Previously my knowledge of React was primarily in the realm of class-based components, some Redux, and passing down the state through components that did not directly use or modify that state. I did not want to use the example React application created for the Rock, Paper, Scissors tutorial even though I found the model, view, controller paradigm to be a very clear and straightforward approach to building the dApp. I wanted to write the whole application from scratch, all the way down to setting up Webpack 5 instead of using the much more commonly used `npx create-react-app myapp`. However, I did use the tutorial application as a reference for interacting with the contract. Since the Reach stdlib is for web-based applications, it didn’t matter what library or framework I used to create the application.

Enhancements

I was able to finish developing the basic functionality of the app with an easy-to-use UI for my hackathon submission. As I mentioned earlier, I kept the application simple to complete it on time. Now that the competition is over, I’m focused on adding the nice-to-have features and getting it completely ready to deploy and use throughout the world (when I’m not polishing my silver medal, that is). One major feature that I’ve yet to implement is the ability to pair users together without selecting whether to play as the Deployer or the Attacher. I would like to add buttons to allow the user to either create a new game (setting their own wager) or join an existing game (accept someone else’s wager). I plan on handling this through either Socket.io or WebRTC. Of course, I’ll also need a server to manage and store the various games being created. There is much to think about as it relates to developing this part of the application. I’ll begin developing that portion now that this article is complete.

Another feature I’d like to add to the application is the ability to take turns guessing between players. The reason I chose not to add it to the base application is because I’d have to send the selected ships to the opponent in order to reveal whether the guess they made hit a ship. I’m still not entirely sure how to securely go about doing this (yet another challenge to tackle now that I’ve finished the article).

Recommendation

Now, with all this said and done, I cannot recommend Reach enough. Yes, it is still in development. There are still some quirks (e.g. iterating over an array) that need to be resolved. But the Reach team is on it. I’m confident that, in the near future, Reach will become the language of choice for developers looking to create smart contracts on a variety of networks.

For now, Reach is built to work with Ethereum and Algorand with support for other protocols on the way. If you haven’t realized this already, this means the most important feature of Reach is being able to write contracts once and safely deploy them anywhere. Equally important is the abstraction from having to write contracts in a blockchain’s native language. This makes writing contracts much easier. Reach is built to help developers avoid common pitfalls that come with writing contracts, such as being able to run assertions from within the contract itself to verify that there are no vulnerabilities. Reach automatically verifies the safety and correctness of your code as it compiles, making it easy to avoid many common pitfalls of a first-time dApp developer.

Another very important feature of Reach is being able to run and test the contract with minimal effort on the developer’s part. Take Ethereum, for example. In order to test a contract, you must first download and configure a local testnet. Then, you copy addresses and private keys generated by that testnet into your application as you are developing the app in order to test the features you built. This is now all handled simply by calling `reach run`. Paired with the .mjs file, testing your contract couldn’t be easier. Simply write interfacing methods within the .mjs file and run Reach. The devnet will be deployed and the .mjs file will run. The compiler will verify any vulnerabilities and the output of the interface methods will be logged to the console. No need to build an entire application to interface with the contract only to later find that there are flaws in the contract. Instead, with one simple command, developers can rapidly validate their code and move on to the UI — confident their contract is ready for deployment.

--

--