What is Battleship?
Battleship is a fun game that involves strategy and luck! You play it on a 10 x 10 grid where each player lays out 5 ships. Each player then alternates to attempt a hit in every turn. The goal is to destroy all of the opponent's ships.
Why I wanted to make Battleship in Power Apps?
I have always had a fascination to rebuild apps that I use everyday, or games that I play everyday, using Power Apps. Why? I am not sure. May be it is the fascination to stretch the platform to its limits in trying to implement complex logic. May be it is because I like to prove that just because it is a low-code platform, that it isn't a joke.
Battleship game building approach
For a change, I had a very well laid out approach to getting this game built out. They were not necessarily in the sequence of how these will be used/needed in the gameplay.
- Create a board
- Lay out ships in a fixed position
- Make computer moves intelligent (more about this below)
- Add different difficulty levels (this was easy once the most complex difficulty level was ironed out)
- Lay out ships horizontally or vertically, keeping the ships within the board
- Make the computer lay out ships randomly
- Switch turns automatically between computer and the user
Battleship game logic approach
I will highlight some of the complex pieces of logic that I had to use in this app:
Creating a board
- I use a nested Sequence(10) to create a collection of 100 records(cells) with the following columns: Row, Column, IsHit, and HasShip
Laying out ships
- I create another collection to store the cells that have ships with these columns: Row, Column, Name, IsHit
- I use this collection when validating a user's layout of ships. To ensure there were no overlapping ships, I simply check if there are more than 2 records in this collection with the same row and column. To ensure all ships were within the board, I check if a ship is on an edge row and then depending on its orientation (horizontal vs vertical), if it has enough cells available (right/left or up/down).
Making the computer moves intelligent:
- I started by making computer moves completely random. After every turn, I mark the cell as "hit" and then filter out the cells that have been hit to create a pool to search from for the next turn. I use this logic as the "Easy" difficulty level.
- Next, to make the computer smarter, I look for cells around (up/down/right/left) after a successful hit. I do that until I get a miss and then I go back to random moves. I store a successful hit in a variable and then I calculate the set of available moves for the next turn by filtering the 4 cells around that hit (up, down, right, and left) excluding any that were hit earlier (using the IsHit flag). I try all 4 until I get another hit. After that, I try the cells around that second hit and so on.
- To add even more intelligence to the computer's move, I needed to store more values in memory. The test case I used was a ship of 5 cells and the 1st hit being in the middle. Since this is a hit, just like in the medium difficulty level, I use the 4 cells around it as the next set of available moves. Then I use the 2nd hit to define the direction of hitting - horizontal (left or right) vs vertical (up or down). Assuming the direction is horizontal right, I then go for the cell on the right of the previous hit. Once I encounter a miss and since the current ship hasn't been destroyed, I then go back to the 1st successful hit and move in the reverse direction (horizontal and left). I then continue to go on until all cells of the current ship get destroyed.
Making the computer layout ships randomly:
- After positioning the 1st ship randomly (ensuring its within the board), I first randomly assign an orientation to the 2nd ship. Then, I randomly pick a starting position from the list of cells that have not been hit. Assuming this ship has 3 cells and is oriented vertically, I collect all cells where the row is 7 or less. Then I loop through each one of them, to collect those cells where the following cells have not been hit:
- Column = same as current cell's column & Row = same as current cell's row
- Column = same as current cell's column & Row = same as current cell's row + 1
- Column = same as current cell's column & Row = same as current cell's row + 2
- And then from this subset, I pick a cell randomly to pick the starting point for the 2nd ship
- I then update the collection used to populate the board (from the 1st point above) to mark these cells (column = starting cell's column & row = starting cell's row, column = starting cell's column & row = starting cell's row + 1, column = starting cell's column & row = starting cell's row + 2, with column HasShip set to true. I also update the collection of ships (from the 2nd point above) to mark these cells with the column HasShip set to true.
Conclusion
As you can see, there were many interesting and challenging pieces of logic that I had to solve for in order to make Battleship with Power Apps. I understand that the logic explained here is at a very high level, but the idea is to introduce the concepts so that when you review the app's code, you will have some background context to better understand the code.
Battleship code
I have uploaded the ZIP and MSAPP files of my Battleship app here: Battleship code.
To learn how to import an app file, click here.
Recent articles
- How to fix a weird behavior with search function?
- How to choose between the different types of Power Apps
- How to make Power Apps more accessible?