-
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.
- Loading branch information
Showing
35 changed files
with
1,616 additions
and
8 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> |
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); | ||
} | ||
} |
16 changes: 16 additions & 0 deletions
16
src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperElementIdentifiers.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,16 @@ | ||
package edu.rpi.legup.puzzle.minesweeper; | ||
|
||
public class MinesweeperElementIdentifiers { | ||
|
||
/** ID for unset Minesweeper elements */ | ||
public static final String UNSET = "MINESWEEPER-UNSET"; | ||
|
||
/** ID for bomb Minesweeper elements */ | ||
public static final String BOMB = "MINESWEEPER-BOMB"; | ||
|
||
/** ID for empty Minesweeper elements */ | ||
public static final String EMPTY = "MINESWEEPER-EMPTY"; | ||
|
||
/** ID for flag Minesweeper elements */ | ||
public static final String FLAG = "MINESWEEPER-FLAG"; | ||
} |
Oops, something went wrong.