Course:CPSC312-2021/HaskellMinesweeper

From UBC Wiki

Haskell Minesweeper

Authors: Dennis Truong and Ivan Gill

What is the problem?

We want to know if we can use Haskell to implement a working version of Minesweeper. Here is a link to the wikipedia article for clarification on the game’s rules: https://en.wikipedia.org/wiki/Minesweeper_(video_game). Basically, we plan to generate a board with mines hidden at randomized locations, and then allow the user to select cells. If the user selects a cell with a mine, they lose. If the user selects a cell without a mine, they will be told the number of adjacent cells that have a mine. The user can then select another cell. The user wins when they have selected all cells without a mine.

What is the something extra?

A challenging aspect of implementing minesweeper is the randomization of bomb locations. Ideally we would like to bring this game outside the console terminal and have it playable through a user interface and typical minesweeper mouse controls.

What did we learn from doing this?

We did not implement a GUI that allows users to click cells, as it became too ambitious a task for us to complete on time, given the amount of effort we ended up putting in just to make the game work. The interface of the game was instead implemented using IO terminal inputs and outputs.

We gained a clearer understanding of how IO works, by implementing the terminal interface from scratch by ourselves. We also gained a clearer understanding of how pseudorandom number generation works in a functional programming language. It is impossible to introduce randomness without using IO, as purely functional programming functions will output identical results when provided identical inputs. We also learned the importance of designing your program before actually writing code in a functional programming language. Since information on the state of the program must be passed function-to-function, as opposed to stored globally, it is important to determine all the information you will need in your state before implementing it and the associated functions. We did not store the number of mines adjacent to each cell in our implemented state, and later realized we needed it. The flexibility of a functional programming approach allowed us to introduce some new state variables to pass between the necessary functions, but our code would have been simpler if we realized we needed those values in our overall state earlier.

We believe functional programming is suitable for developing a Minesweeper game. Essentially, a Minesweeper game is a series of expressions that take in a board, and output a new board given some action. As neither the information required to represent actions or the board is especially complex, we were able to easily implement the game as a series of functions that pass the state of the board to each other, while occasionally asking the user to input an action.

We believe a non-functional programming approach to implementing a Minesweeper game, where the state of the board was modified externally, would have offered several disadvantages. First, there would be the possibility of introducing bugs from expressions modifying state in the incorrect order, or modifying a stale state already updated by another expression. Our program avoids this by passing the state between one function at a time. Second, it would be more difficult to test the various paths a user can take within the game, since they may rely on the corresponding execution of distinct code blocks, or the state of external variables. Our program avoids this by restricting all code associated with a single path to one function (and sometimes a helper function). Third, the code could be more difficult to extend. Introducing new steps and paths in our Minesweeper game is as simple as adding new functions into the series of independent functions we have already implemented. For example, we could introduce a function after AskForAction that asks users if they want us to clear a single cell for them as a hint. With a non-functional approach, introducing new expressions could be more difficult, as many expressions could rely on the side effects of other expressions, and the global state of the program.

Links to code etc

https://github.com/ivansg44/HaskellMinesweeper