-
Notifications
You must be signed in to change notification settings - Fork 82
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Initial Minesweeper implementation work * Add Unset tile type * Init elements Created initial classes for bomb, flag, utilities, and contradiction rule. * Make clicking tiles cycle between numbers, bomb, and empty tiles. * Fix checkstyle errors * Added * Revert "Added" This reverts commit 89fbe94. * Added * Create 123456 * Revert "Create 123456" This reverts commit ace7122. * Created Bomb or Filled Case Rule * Update BombOrFilledCaseRule.java removed fillapix imports * Various additions Added the unset puzzle element, added the minesweeper board copy function, fixed the bomb or filled case rule * Revert "Create 123456" This reverts commit ace7122. * Update Minesweeper classes to use newer Java features * Add documentation to Minesweeper classes * Added helper functions to utilities class Added helper functions used for getting cells adjacent to flag, as well as combinations of possible bomb tiles. * Added function to retrieve a tile's number * Create SatisfyFlagCaseRule.java * Fixed "bomb or filled" case rule's picture * Fixed "satisfy flag" case rule's picture * Add some methods to MinesweeperUtilities and created some tests to verify the getSurroundingCells function works as expected. * temp * Added BombOrFilledCaseRule * Revert "temp" This reverts commit b4c8ed9. * Update minesweeperUtilities.java * Add bomb image * Added reference sheet for Minesweeper tiles for puzzle editor * Added Minesweeper Utility Functions -Fixed Bomb or Filled case rule picture -Added getTileNumber and setCellType functions -added 5x5 test puzzle * Fixed "satisfy flag" case rule * Automated Java code formatting changes * Revert "Automated Java code formatting changes" This reverts commit f9d52a3. * Added "More Bombs Than Flag" Contradiction Rule * Delete Unset (replaced by UnsetTile) * Added dot to empty tile image * Fixed "Satisfy Flag" Case Rule Picture * Fixed "satisfy flag" bug fixed bug where "satisfy flag" allowed you to select an empty tile instead of a flag tile * Added "Finish With Bombs" Direct Rule * Update FinishWithBombsDirectRule.java * Automated Java code formatting changes * Automated Java code formatting changes --------- Co-authored-by: Fisher <[email protected]> Co-authored-by: FisherLuba <[email protected]> Co-authored-by: philippark <[email protected]> Co-authored-by: Chase Grajeda <[email protected]> Co-authored-by: Bram van Heuveln <[email protected]> Co-authored-by: Charles Tian <[email protected]>
- Loading branch information
1 parent
58eba41
commit d68859b
Showing
51 changed files
with
2,061 additions
and
539 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||
<Legup version="2.0.0"> | ||
<puzzle name="Minesweeper"> | ||
<board height="5" width="5"> | ||
<cells> | ||
|
||
</cells> | ||
</board> | ||
</puzzle> | ||
<solved isSolved="false" lastSaved="--"/> | ||
</Legup> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
64 changes: 64 additions & 0 deletions
64
src/main/java/edu/rpi/legup/puzzle/minesweeper/Minesweeper.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
package edu.rpi.legup.puzzle.minesweeper; | ||
|
||
import edu.rpi.legup.model.Puzzle; | ||
import edu.rpi.legup.model.gameboard.Board; | ||
import edu.rpi.legup.model.gameboard.PuzzleElement; | ||
import edu.rpi.legup.model.rules.ContradictionRule; | ||
import org.jetbrains.annotations.Contract; | ||
import org.jetbrains.annotations.NotNull; | ||
import org.jetbrains.annotations.Nullable; | ||
|
||
public class Minesweeper extends Puzzle { | ||
|
||
public static final String NAME = "Minesweeper"; | ||
|
||
public Minesweeper() { | ||
this.name = NAME; | ||
this.importer = new MinesweeperImporter(this); | ||
this.exporter = new MinesweeperExporter(this); | ||
this.factory = MinesweeperCellFactory.INSTANCE; | ||
} | ||
|
||
@Override | ||
@Contract(pure = false) | ||
public void initializeView() { | ||
this.boardView = new MinesweeperView((MinesweeperBoard) this.currentBoard); | ||
this.boardView.setBoard(this.currentBoard); | ||
addBoardListener(boardView); | ||
} | ||
|
||
@Override | ||
@Contract("_ -> null") | ||
public @Nullable Board generatePuzzle(int difficulty) { | ||
return null; | ||
} | ||
|
||
@Override | ||
@Contract(pure = true) | ||
public boolean isBoardComplete(@NotNull Board board) { | ||
MinesweeperBoard minesweeperBoard = (MinesweeperBoard) board; | ||
|
||
for (ContradictionRule rule : contradictionRules) { | ||
if (rule.checkContradiction(minesweeperBoard) == null) { | ||
return false; | ||
} | ||
} | ||
for (PuzzleElement<?> data : minesweeperBoard.getPuzzleElements()) { | ||
final MinesweeperCell cell = (MinesweeperCell) data; | ||
if (cell.getData().equals(MinesweeperTileData.empty())) { | ||
return false; | ||
} | ||
} | ||
return true; | ||
} | ||
|
||
@Override | ||
@Contract(pure = true) | ||
public void onBoardChange(@NotNull Board board) {} | ||
|
||
@Override | ||
@Contract(pure = true) | ||
public boolean isValidDimensions(int rows, int columns) { | ||
return rows >= 1 && columns >= 1; | ||
} | ||
} |
36 changes: 36 additions & 0 deletions
36
src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperBoard.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package edu.rpi.legup.puzzle.minesweeper; | ||
|
||
import edu.rpi.legup.model.gameboard.GridBoard; | ||
|
||
public class MinesweeperBoard extends GridBoard { | ||
|
||
public MinesweeperBoard(int width, int height) { | ||
super(width, height); | ||
} | ||
|
||
public MinesweeperBoard(int size) { | ||
super(size); | ||
} | ||
|
||
@Override | ||
public MinesweeperCell getCell(int x, int y) { | ||
return (MinesweeperCell) super.getCell(x, y); | ||
} | ||
|
||
/** | ||
* Performs a deep copy of the Board | ||
* | ||
* @return a new copy of the board that is independent of this one | ||
*/ | ||
@Override | ||
public MinesweeperBoard copy() { | ||
MinesweeperBoard newMinesweeperBoard = | ||
new MinesweeperBoard(this.dimension.width, this.dimension.height); | ||
for (int x = 0; x < this.dimension.width; x++) { | ||
for (int y = 0; y < this.dimension.height; y++) { | ||
newMinesweeperBoard.setCell(x, y, getCell(x, y).copy()); | ||
} | ||
} | ||
return newMinesweeperBoard; | ||
} | ||
} |
73 changes: 73 additions & 0 deletions
73
src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperCell.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
package edu.rpi.legup.puzzle.minesweeper; | ||
|
||
import edu.rpi.legup.model.elements.Element; | ||
import edu.rpi.legup.model.gameboard.GridCell; | ||
import java.awt.*; | ||
import java.awt.event.MouseEvent; | ||
import org.jetbrains.annotations.Contract; | ||
import org.jetbrains.annotations.NotNull; | ||
|
||
public class MinesweeperCell extends GridCell<MinesweeperTileData> { | ||
|
||
public MinesweeperCell(@NotNull MinesweeperTileData value, @NotNull Point location) { | ||
super(value, location); | ||
} | ||
|
||
public @NotNull MinesweeperTileType getTileType() { | ||
return super.data.type(); | ||
} | ||
|
||
public @NotNull int getTileNumber() { | ||
return super.data.data(); | ||
} | ||
|
||
@Override | ||
@Contract(pure = false) | ||
/** Sets this cell's data to the value specified by {@link Element#getElementID()} */ | ||
public void setType(@NotNull Element element, @NotNull MouseEvent event) { | ||
switch (element.getElementID()) { | ||
case MinesweeperElementIdentifiers.BOMB -> { | ||
this.data = MinesweeperTileData.bomb(); | ||
break; | ||
} | ||
case MinesweeperElementIdentifiers.FLAG -> { | ||
final int currentData = super.data.data(); | ||
switch (event.getButton()) { | ||
case MouseEvent.BUTTON1 -> { | ||
if (currentData >= 8) { | ||
this.data = MinesweeperTileData.empty(); | ||
return; | ||
} | ||
this.data = MinesweeperTileData.flag(currentData + 1); | ||
return; | ||
} | ||
case MouseEvent.BUTTON2, MouseEvent.BUTTON3 -> { | ||
if (currentData <= 0) { | ||
this.data = MinesweeperTileData.empty(); | ||
return; | ||
} | ||
this.data = MinesweeperTileData.flag(currentData - 1); | ||
return; | ||
} | ||
} | ||
} | ||
default -> { | ||
this.data = MinesweeperTileData.empty(); | ||
} | ||
} | ||
} | ||
|
||
public void setCellType(MinesweeperTileData type) { | ||
this.data = type; | ||
} | ||
|
||
@Override | ||
@Contract(pure = true) | ||
public @NotNull MinesweeperCell copy() { | ||
MinesweeperCell copy = new MinesweeperCell(data, (Point) location.clone()); | ||
copy.setIndex(index); | ||
copy.setModifiable(isModifiable); | ||
copy.setGiven(isGiven); | ||
return copy; | ||
} | ||
} |
101 changes: 101 additions & 0 deletions
101
src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperCellFactory.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
package edu.rpi.legup.puzzle.minesweeper; | ||
|
||
import edu.rpi.legup.model.gameboard.Board; | ||
import edu.rpi.legup.model.gameboard.ElementFactory; | ||
import edu.rpi.legup.model.gameboard.PuzzleElement; | ||
import edu.rpi.legup.save.InvalidFileFormatException; | ||
import java.awt.*; | ||
import org.jetbrains.annotations.Contract; | ||
import org.jetbrains.annotations.NotNull; | ||
import org.w3c.dom.Document; | ||
import org.w3c.dom.Element; | ||
import org.w3c.dom.NamedNodeMap; | ||
import org.w3c.dom.Node; | ||
|
||
public class MinesweeperCellFactory extends ElementFactory { | ||
|
||
/** The key of the data used in {@link NamedNodeMap} */ | ||
private static final String DATA_ATTRIBUTE = "data"; | ||
|
||
/** The key of the x position used in {@link NamedNodeMap} */ | ||
private static final String X_ATTRIBUTE = "x"; | ||
|
||
/** The key of the y position used in {@link NamedNodeMap} */ | ||
private static final String Y_ATTRIBUTE = "y"; | ||
|
||
private MinesweeperCellFactory() {} | ||
|
||
public static final MinesweeperCellFactory INSTANCE = new MinesweeperCellFactory(); | ||
|
||
/** | ||
* @param node node that represents the puzzleElement | ||
* @param board Board to use to verify the newly created {@link MinesweeperCell} is valid | ||
* @return a new {@link MinesweeperCell} | ||
* @throws InvalidFileFormatException If the node name is not "cell" | ||
* @throws NumberFormatException If the {@link #X_ATTRIBUTE} or {@link #Y_ATTRIBUTE} is not a | ||
* number | ||
* @throws NullPointerException If one of {@link #DATA_ATTRIBUTE}, {@link #X_ATTRIBUTE} or | ||
* {@link #Y_ATTRIBUTE} does not exist. | ||
*/ | ||
@Override | ||
@Contract(pure = false) | ||
public @NotNull PuzzleElement<MinesweeperTileData> importCell( | ||
@NotNull Node node, @NotNull Board board) throws InvalidFileFormatException { | ||
try { | ||
if (!node.getNodeName().equalsIgnoreCase("cell")) { | ||
throw new InvalidFileFormatException( | ||
"Minesweeper Factory: unknown puzzleElement puzzleElement"); | ||
} | ||
|
||
MinesweeperBoard minesweeperBoard = (MinesweeperBoard) board; | ||
final int width = minesweeperBoard.getWidth(); | ||
final int height = minesweeperBoard.getHeight(); | ||
|
||
final NamedNodeMap attributeList = node.getAttributes(); | ||
final int value = | ||
Integer.parseInt(attributeList.getNamedItem(DATA_ATTRIBUTE).getNodeValue()); | ||
final int x = Integer.parseInt(attributeList.getNamedItem(X_ATTRIBUTE).getNodeValue()); | ||
final int y = Integer.parseInt(attributeList.getNamedItem(Y_ATTRIBUTE).getNodeValue()); | ||
if (x >= width || y >= height) { | ||
throw new InvalidFileFormatException( | ||
"Minesweeper Factory: cell location out of bounds"); | ||
} | ||
if (value < -2) { | ||
throw new InvalidFileFormatException("Minesweeper Factory: cell unknown value"); | ||
} | ||
final MinesweeperCell cell = | ||
new MinesweeperCell(MinesweeperTileData.fromData(value), new Point(x, y)); | ||
cell.setIndex(y * height + x); | ||
return cell; | ||
} catch (NumberFormatException e) { | ||
throw new InvalidFileFormatException( | ||
"Minesweeper Factory: unknown value where integer expected"); | ||
} catch (NullPointerException e) { | ||
throw new InvalidFileFormatException( | ||
"Minesweeper Factory: could not find attribute(s)"); | ||
} | ||
} | ||
|
||
/** | ||
* @param document Document used to create the element | ||
* @param puzzleElement PuzzleElement cell | ||
* @return a {@link Element} that contains the {@link #DATA_ATTRIBUTE}, {@link #X_ATTRIBUTE}, | ||
* and {@link #Y_ATTRIBUTE} | ||
*/ | ||
@Override | ||
@Contract(pure = false) | ||
public @NotNull Element exportCell( | ||
@NotNull Document document, | ||
@SuppressWarnings("rawtypes") @NotNull PuzzleElement puzzleElement) { | ||
org.w3c.dom.Element cellElement = document.createElement("cell"); | ||
|
||
MinesweeperCell cell = (MinesweeperCell) puzzleElement; | ||
Point loc = cell.getLocation(); | ||
|
||
cellElement.setAttribute(DATA_ATTRIBUTE, String.valueOf(cell.getData())); | ||
cellElement.setAttribute(X_ATTRIBUTE, String.valueOf(loc.x)); | ||
cellElement.setAttribute(Y_ATTRIBUTE, String.valueOf(loc.y)); | ||
|
||
return cellElement; | ||
} | ||
} |
57 changes: 57 additions & 0 deletions
57
src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
package edu.rpi.legup.puzzle.minesweeper; | ||
|
||
import edu.rpi.legup.controller.ElementController; | ||
import edu.rpi.legup.model.gameboard.PuzzleElement; | ||
import java.awt.event.MouseEvent; | ||
import org.jetbrains.annotations.Contract; | ||
import org.jetbrains.annotations.NotNull; | ||
|
||
public class MinesweeperController extends ElementController { | ||
|
||
/** | ||
* If the button clicked was button 1, then {@link MinesweeperTileData#fromData(int)} is called | ||
* with a value of {@code current.data() + 1}. If the button clicked was button 2 or 3, then | ||
* {@link MinesweeperTileData#fromData(int)} is called with a value of {@code currentData() - 1} | ||
* Otherwise {@link MinesweeperTileData#empty()} is returned. | ||
* | ||
* @param event The user's click data | ||
* @param current The current data at the cell they clicked on | ||
* @return A different cell data depending on what the current data is | ||
*/ | ||
@Contract(pure = true) | ||
public static @NotNull MinesweeperTileData getNewCellDataOnClick( | ||
@NotNull MouseEvent event, @NotNull MinesweeperTileData current) { | ||
final int numberData = current.data(); | ||
return switch (event.getButton()) { | ||
case MouseEvent.BUTTON1 -> MinesweeperTileData.fromData(numberData + 1); | ||
case MouseEvent.BUTTON2, MouseEvent.BUTTON3 -> | ||
MinesweeperTileData.fromData(numberData - 1); | ||
default -> MinesweeperTileData.empty(); | ||
}; | ||
} | ||
|
||
/** | ||
* @see #getNewCellDataOnClick(MouseEvent, MinesweeperTileData) | ||
* @param event The user's click data | ||
* @param data The current data at the cell they clicked on | ||
*/ | ||
@Override | ||
@SuppressWarnings("unchecked") | ||
@Contract(pure = false) | ||
public void changeCell( | ||
@NotNull MouseEvent event, @SuppressWarnings("rawtypes") @NotNull PuzzleElement data) { | ||
final MinesweeperCell cell = (MinesweeperCell) data; | ||
if (event.isControlDown()) { | ||
this.boardView | ||
.getSelectionPopupMenu() | ||
.show( | ||
boardView, | ||
this.boardView.getCanvas().getX() + event.getX(), | ||
this.boardView.getCanvas().getY() + event.getY()); | ||
return; | ||
} | ||
|
||
final MinesweeperTileData newData = getNewCellDataOnClick(event, cell.getData()); | ||
data.setData(newData); | ||
} | ||
} |
Oops, something went wrong.