Play Minesweeper by formally proving your moves in Idris
Haskell
171
19 commits
updated Sep 25, 2024
ProofSweeper is a variant of the classic Minesweeper game in which, to advance in the game, you must formally prove that a cell is or is not a mine using Idris. The game is designed as a fun way to improve your ability to write formal proofs in Idris.
It is played on a square grid of cells (2x2 up to 20x20, selected when you create a new game). The game is played by using a command-line utility called the ProofSweeperEngine to control game flow, and by writing proofs in your favourite text editor.
The ProofSweeperEngine is responsible for generating the axioms (things known to be true, e.g. that a certain cell is not a mine but is touching 2 mines) resulting from the current state of the game. It also produces a console visualisation of the state of play to help you plan what formal proofs you want to make. When you have a formal proof, the ProofSweeperEngine is also responsible for invoking Idris to validate your proof is valid, and updating everything for the new state.
idris2 from the command line works before continuing.stack on the command-line before continuing.git clone https://github.com/A1kmm/proofsweeper.git, and change into the proofsweeper directory.stack install. Check that you can run ProofSweeperEngine from the command-line.ProofSweeperEngine new 15 (or whatever board size you want).Typical game-play flow is as follows:
mineAt_x_y or noMineAt_x_y
(where x and y are replaced with the numbers of the coordinate the proof
relates to). You may want to use an Idris environment to verify your proof as you
go.MineFact (MkCoord x y) IsMine or MineFact (MkCoord x y) IsNotMine from the axioms.ProofSweeperEngine move mine x y or ProofSweeperEngine move notmine x y to check your proof. If it is accepted, the axioms will be updated (which, in the case of a non-mine, will likely expose new information in the count of adjacent mines), and a new ASCII art representation of the board will be printed.ProofSweeperEngine hint x y command to expose any unknown cell, which might provide enough information to continue proving.ProofSweeperEngine print command.game.data - it contains the full state of the game,
including 'unknown' cells.hint command and compete
with others to see who uses it the least to complete the board!Four additional axioms are provided (currently constructed with believe_me), on the premise that it should be impossible to improve that the same cell is both a mine and a non-mine. These are useful for proofs by contradiction.
The ProofSweeperLemmas file comes with some useful lemmas that can help you to prove things.
eqTestIsEqCoord is a useful lemma that proves that if use compare two coordinates, and the comparison comes out true, then the coordinates are the same. Since list operations rely on comparison, and the axioms use lists, this is a very useful lemma.
ifWithProof lets you handle the true and false case, and passes in a proof that it is in fact true or false to each branch.
trueForAllListElems lets you deal with statements of the form: for all v, given that v is in some list, then some proposition p holds for all v. You need to supply the elements of the list, plus a proof for each element of the list. You also need to supply the proposition p, and the proof that an equality comparison returning true means the elements are equal. This is most usefully used with lists of Coords - in which case you can use eqTestIsEqCoord to provide the proof that true equality comparison means equality.
The top of ProofSweeperPlay-Example.idr provides a useful template for constructing your own ProofSweeperPlay.idr to play the game. It also shows two common tactics you can use to prove things in ProofSweeper.
In the first example, we want to prove that (14,9) is a mine. On a 15x15 board,
(14,9) is right up against the right wall, so it only has 5 neighbours. It was
known axiomatically that (14,10) is a non-mine with one neighbour. It was also
known axiomatically that the other 4 neighbours (apart from (14,9)), namely
(13,9), (13,10), (13,11), and (14,11), are not mines. Using the
AllMinesAccountedFor constructor, it was possible to construct
MineFact (MkCoord 14 9) IsMine and run ProofSweeperEngine move mine 14 9 to
check the proof and mark (14,9) as a mine. Notice the naming of the
proof as mineAt_14_9 - ProofSweeperEngine expects this naming scheme to be followed.
Further down in the example, a more complex proof is constructed. The layout of
mines means that x cannot possibly be a mine, because that would create a
contradiction. Refer to the comments in ProofSweeperPlay-Example.idr to see how
the player assumed that XCoord ((12,13)) was a mine, and proved that this led
to a contradiction (leading to the construction of Void). This contradiction
disproved that it was a mine, and notMineImpliesNonMine was used to construct a proof
that XCoord was not a mine.
10 commits
9 commits
Haskell
66.7%
Idris
33.3%
Play Minesweeper by formally proving your moves in Idris
Haskell
171
19 commits
updated Sep 25, 2024
ProofSweeper is a variant of the classic Minesweeper game in which, to advance in the game, you must formally prove that a cell is or is not a mine using Idris. The game is designed as a fun way to improve your ability to write formal proofs in Idris.
It is played on a square grid of cells (2x2 up to 20x20, selected when you create a new game). The game is played by using a command-line utility called the ProofSweeperEngine to control game flow, and by writing proofs in your favourite text editor.
The ProofSweeperEngine is responsible for generating the axioms (things known to be true, e.g. that a certain cell is not a mine but is touching 2 mines) resulting from the current state of the game. It also produces a console visualisation of the state of play to help you plan what formal proofs you want to make. When you have a formal proof, the ProofSweeperEngine is also responsible for invoking Idris to validate your proof is valid, and updating everything for the new state.
idris2 from the command line works before continuing.stack on the command-line before continuing.git clone https://github.com/A1kmm/proofsweeper.git, and change into the proofsweeper directory.stack install. Check that you can run ProofSweeperEngine from the command-line.ProofSweeperEngine new 15 (or whatever board size you want).Typical game-play flow is as follows:
mineAt_x_y or noMineAt_x_y
(where x and y are replaced with the numbers of the coordinate the proof
relates to). You may want to use an Idris environment to verify your proof as you
go.MineFact (MkCoord x y) IsMine or MineFact (MkCoord x y) IsNotMine from the axioms.ProofSweeperEngine move mine x y or ProofSweeperEngine move notmine x y to check your proof. If it is accepted, the axioms will be updated (which, in the case of a non-mine, will likely expose new information in the count of adjacent mines), and a new ASCII art representation of the board will be printed.ProofSweeperEngine hint x y command to expose any unknown cell, which might provide enough information to continue proving.ProofSweeperEngine print command.game.data - it contains the full state of the game,
including 'unknown' cells.hint command and compete
with others to see who uses it the least to complete the board!Four additional axioms are provided (currently constructed with believe_me), on the premise that it should be impossible to improve that the same cell is both a mine and a non-mine. These are useful for proofs by contradiction.
The ProofSweeperLemmas file comes with some useful lemmas that can help you to prove things.
eqTestIsEqCoord is a useful lemma that proves that if use compare two coordinates, and the comparison comes out true, then the coordinates are the same. Since list operations rely on comparison, and the axioms use lists, this is a very useful lemma.
ifWithProof lets you handle the true and false case, and passes in a proof that it is in fact true or false to each branch.
trueForAllListElems lets you deal with statements of the form: for all v, given that v is in some list, then some proposition p holds for all v. You need to supply the elements of the list, plus a proof for each element of the list. You also need to supply the proposition p, and the proof that an equality comparison returning true means the elements are equal. This is most usefully used with lists of Coords - in which case you can use eqTestIsEqCoord to provide the proof that true equality comparison means equality.
The top of ProofSweeperPlay-Example.idr provides a useful template for constructing your own ProofSweeperPlay.idr to play the game. It also shows two common tactics you can use to prove things in ProofSweeper.
In the first example, we want to prove that (14,9) is a mine. On a 15x15 board,
(14,9) is right up against the right wall, so it only has 5 neighbours. It was
known axiomatically that (14,10) is a non-mine with one neighbour. It was also
known axiomatically that the other 4 neighbours (apart from (14,9)), namely
(13,9), (13,10), (13,11), and (14,11), are not mines. Using the
AllMinesAccountedFor constructor, it was possible to construct
MineFact (MkCoord 14 9) IsMine and run ProofSweeperEngine move mine 14 9 to
check the proof and mark (14,9) as a mine. Notice the naming of the
proof as mineAt_14_9 - ProofSweeperEngine expects this naming scheme to be followed.
Further down in the example, a more complex proof is constructed. The layout of
mines means that x cannot possibly be a mine, because that would create a
contradiction. Refer to the comments in ProofSweeperPlay-Example.idr to see how
the player assumed that XCoord ((12,13)) was a mine, and proved that this led
to a contradiction (leading to the construction of Void). This contradiction
disproved that it was a mine, and notMineImpliesNonMine was used to construct a proof
that XCoord was not a mine.
10 commits
9 commits
Haskell
66.7%
Idris
33.3%