diff --git a/puzzles files/thermometer/therm_test.xml b/puzzles files/thermometer/therm_test.xml
new file mode 100644
index 000000000..66e841dc5
--- /dev/null
+++ b/puzzles files/thermometer/therm_test.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/Thermometer.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/Thermometer.java
new file mode 100644
index 000000000..8138104f5
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/Thermometer.java
@@ -0,0 +1,56 @@
+package edu.rpi.legup.puzzle.thermometer;
+
+import edu.rpi.legup.model.Puzzle;
+import edu.rpi.legup.model.gameboard.Board;
+
+// basically just copy-pasted from dev guide on wiki
+public class Thermometer extends Puzzle {
+ public Thermometer() {
+ super();
+
+ this.name = "Thermometer";
+
+ this.importer = new ThermometerImporter(this);
+ this.exporter = new ThermometerExporter(this);
+ // we do not have a thermometerCellFactory class as
+ // thermometerVial has its own thermometerCell factory method
+ }
+
+ /** Initializes the game board. Called by the invoker of the class */
+ @Override
+ public void initializeView() {
+ boardView = new ThermometerView((ThermometerBoard) currentBoard);
+ boardView.setBoard(currentBoard);
+ addBoardListener(boardView);
+ }
+
+ /**
+ * Generates a random edu.rpi.legup.puzzle based on the difficulty
+ *
+ * @param difficulty level of difficulty (1-10)
+ * @return board of the random edu.rpi.legup.puzzle
+ */
+ @Override
+ public Board generatePuzzle(int difficulty) {
+ return null;
+ }
+
+ /**
+ * Determines if the current board is a valid state
+ *
+ * @param board board to check for validity
+ * @return true if board is valid, false otherwise
+ */
+ @Override
+ public boolean isBoardComplete(Board board) {
+ return true;
+ }
+
+ /**
+ * Callback for when the board puzzleElement changes
+ *
+ * @param board the board that has changed
+ */
+ @Override
+ public void onBoardChange(Board board) {}
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerBoard.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerBoard.java
new file mode 100644
index 000000000..95ff7ff83
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerBoard.java
@@ -0,0 +1,139 @@
+package edu.rpi.legup.puzzle.thermometer;
+
+import edu.rpi.legup.model.gameboard.GridBoard;
+import java.awt.*;
+import java.util.ArrayList;
+
+public class ThermometerBoard extends GridBoard {
+
+ // an array containing all of our vials on the board
+ private ArrayList thermometerVials;
+
+ // representations of the number requirements along rows and columns of the board
+ // we use rotation to store the number
+ private ArrayList colNumbers;
+ private ArrayList rowNumbers;
+
+ private ThermometerCell dummyCell;
+
+ // constructors for the boards and variables
+ public ThermometerBoard(int width, int height) {
+ super(width, height);
+
+ // initializing the row/col number arrays with zeros, so they can be
+ // easily updated using the setRow/ColNumber functions
+ colNumbers = new ArrayList<>();
+ for (int i = 0; i < width - 1; i++) {
+ ThermometerCell cell =
+ new ThermometerCell(
+ new Point(i, height - 1),
+ ThermometerType.UNKNOWN,
+ ThermometerFill.UNKNOWN,
+ 0);
+ cell.setIndex((height - 1) * height + i);
+ colNumbers.add(cell);
+ this.setCell(i, height - 1, cell);
+ }
+ rowNumbers = new ArrayList<>();
+ for (int i = 0; i < height - 1; i++) {
+ ThermometerCell cell =
+ new ThermometerCell(
+ new Point(width - 1, i),
+ ThermometerType.UNKNOWN,
+ ThermometerFill.UNKNOWN,
+ 0);
+ cell.setIndex(i * height + (width - 1));
+ rowNumbers.add(cell);
+ this.setCell(width - 1, i, cell);
+ }
+
+ // setting a dummy cell so board doesn't have null cells
+ dummyCell =
+ new ThermometerCell(
+ new Point(width - 1, height - 1),
+ ThermometerType.UNKNOWN,
+ ThermometerFill.UNKNOWN,
+ -1);
+ dummyCell.setIndex((height - 1) * height + width);
+ this.setCell(width - 1, height - 1, dummyCell);
+
+ // creating our empty vial of thermometers to add to
+ thermometerVials = new ArrayList<>();
+ }
+
+ // setters and accessors for our array of vials
+ public void addVial(ThermometerVial v) {
+ thermometerVials.add(v);
+ }
+
+ public ArrayList getVials() {
+ return thermometerVials;
+ }
+
+ // our setters for row/col numbers with simple input verification
+ public boolean setRowNumber(int row, int num) {
+ // first check is to verify we are updating an element in range
+ // second check is to verify the new number can be achieved by the puzzle
+ if (row < rowNumbers.size() && num <= colNumbers.size()) {
+ rowNumbers.get(row).setRotation(num);
+ return true;
+ }
+ return false;
+ }
+
+ public boolean setColNumber(int col, int num) {
+ // first check is to verify we are updating an element in range
+ // second check is to verify the new number can be achieved by the puzzle
+ if (col < colNumbers.size() && num <= rowNumbers.size()) {
+ colNumbers.get(col).setRotation(num);
+ return true;
+ }
+ return false;
+ }
+
+ // basic accessors for row/col numbers
+ public int getRowNumber(int row) {
+ if (row < 0 || row >= rowNumbers.size()) return -1;
+ return rowNumbers.get(row).getRotation();
+ }
+
+ public int getColNumber(int col) {
+ if (col < 0 || col >= rowNumbers.size()) return -1;
+ return colNumbers.get(col).getRotation();
+ }
+
+ // Accessors for saving row/column
+ public ArrayList getRowNumbers() {
+ return rowNumbers;
+ }
+
+ public ArrayList getColNumbers() {
+ return colNumbers;
+ }
+
+ // we all suck at programming so instead of using provided array list
+ // we use our own array lists to keep track of the vials
+ // marginally useful because it means we are guaranteed to get a
+ // thermometer cell when calling get cell, but using some type casting
+ // this override function could very likely be refactored out
+ @Override
+ public ThermometerCell getCell(int x, int y) {
+ for (ThermometerVial vial : this.thermometerVials) {
+ for (ThermometerCell cell : vial.getCells()) {
+ if (cell.getLocation().x == x && cell.getLocation().y == y) return cell;
+ }
+ }
+
+ for (ThermometerCell cell : rowNumbers) {
+ if (cell.getLocation().x == x && cell.getLocation().y == y) return cell;
+ }
+
+ for (ThermometerCell cell : colNumbers) {
+ if (cell.getLocation().x == x && cell.getLocation().y == y) return cell;
+ }
+
+ if (x == this.getWidth() - 1 && y == this.getHeight() - 1) return dummyCell;
+
+ return null;
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerCell.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerCell.java
new file mode 100644
index 000000000..175a455b4
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerCell.java
@@ -0,0 +1,67 @@
+package edu.rpi.legup.puzzle.thermometer;
+
+import edu.rpi.legup.model.gameboard.GridCell;
+import java.awt.Point;
+
+public class ThermometerCell extends GridCell {
+
+ // information about the cell needed to display it
+ private ThermometerType type;
+ private ThermometerFill fill;
+ private int rotation;
+
+ public ThermometerCell(Point location, ThermometerType t, ThermometerFill f, int r) {
+ // since we do not use get/set data value int can be any value
+ super(1, location);
+ type = t;
+ fill = f;
+ rotation = r;
+ }
+
+ // Note: setdata does not work for our purposes
+ public void setType(ThermometerType t) {
+ type = t;
+ }
+
+ public ThermometerType getType() {
+ return type;
+ }
+
+ public void setFill(ThermometerFill f) {
+ fill = f;
+ }
+
+ public ThermometerFill getFill() {
+ return fill;
+ }
+
+ public void setRotation(int r) {
+ rotation = r;
+ }
+
+ public int getRotation() {
+ return rotation;
+ }
+
+ @Override
+ public ThermometerCell copy() {
+ ThermometerCell copy =
+ new ThermometerCell((Point) location.clone(), this.type, this.fill, this.rotation);
+ copy.setIndex(index);
+ copy.setModifiable(isModifiable);
+ copy.setGiven(isGiven);
+ return copy;
+ }
+
+ @Override
+ public String toString() {
+ return "("
+ + location.getX()
+ + ", "
+ + location.getY()
+ + ") TYPE = "
+ + getType()
+ + " FILL = "
+ + getFill();
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerController.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerController.java
new file mode 100644
index 000000000..cd2135bd7
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerController.java
@@ -0,0 +1,44 @@
+package edu.rpi.legup.puzzle.thermometer;
+
+import edu.rpi.legup.controller.ElementController;
+import edu.rpi.legup.model.gameboard.PuzzleElement;
+import java.awt.event.MouseEvent;
+
+public class ThermometerController extends ElementController {
+
+ // method for updating thermometer cells since number cells have unknown for
+ // their fill type we don't need to worry about end user modifying them with this
+ @Override
+ public void changeCell(MouseEvent e, PuzzleElement data) {
+ ThermometerCell cell = (ThermometerCell) data;
+
+ if (e.getButton() == MouseEvent.BUTTON1) {
+ if (e.isControlDown()) {
+ this.boardView
+ .getSelectionPopupMenu()
+ .show(
+ boardView,
+ this.boardView.getCanvas().getX() + e.getX(),
+ this.boardView.getCanvas().getY() + e.getY());
+ } else {
+ if (cell.getFill() == ThermometerFill.EMPTY) {
+ cell.setFill(ThermometerFill.FILLED);
+ } else if (cell.getFill() == ThermometerFill.FILLED) {
+ cell.setFill(ThermometerFill.BLOCKED);
+ } else {
+ cell.setFill(ThermometerFill.EMPTY);
+ }
+ }
+ } else if (e.getButton() == MouseEvent.BUTTON3) {
+ if (cell.getFill() == ThermometerFill.EMPTY) {
+ cell.setFill(ThermometerFill.BLOCKED);
+ } else if (cell.getFill() == ThermometerFill.BLOCKED) {
+ cell.setFill(ThermometerFill.FILLED);
+ } else {
+ cell.setFill(ThermometerFill.EMPTY);
+ }
+ } else if (e.getButton() == MouseEvent.BUTTON2) {
+ System.out.println("[DEBUG] " + cell);
+ }
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerElementView.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerElementView.java
new file mode 100644
index 000000000..0657e95b0
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerElementView.java
@@ -0,0 +1,311 @@
+package edu.rpi.legup.puzzle.thermometer;
+
+import edu.rpi.legup.ui.boardview.GridElementView;
+import java.awt.*;
+import java.io.IOException;
+import javax.imageio.ImageIO;
+
+public class ThermometerElementView extends GridElementView {
+
+ // mixture of stuff stolen from tree tent and dev guide
+ private static final Font FONT = new Font("TimesRoman", Font.BOLD, 16);
+ private static final Color FONT_COLOR = Color.BLACK;
+
+ public ThermometerElementView(ThermometerCell cell) {
+ super(cell);
+ }
+
+ @Override
+ public ThermometerCell getPuzzleElement() {
+ return (ThermometerCell) super.getPuzzleElement();
+ }
+
+ // method for drawing a thermometer cell
+ // basically copy/pasted from tree tent drawing tent images
+ @Override
+ public void drawElement(Graphics2D graphics2D) {
+
+ ThermometerCell cell = (ThermometerCell) puzzleElement;
+ ThermometerType type = cell.getType();
+ ThermometerFill fill = cell.getFill();
+ int rotation = cell.getRotation();
+
+ graphics2D.drawImage(
+ imageSrc(type, fill, rotation),
+ location.x,
+ location.y,
+ size.width,
+ size.height,
+ null,
+ null);
+
+ graphics2D.setColor(Color.BLACK);
+ graphics2D.drawRect(location.x, location.y, size.width, size.height);
+ }
+
+ // modified code from tree trent to display images
+ private Image imageSrc(ThermometerType t, ThermometerFill f, int r) {
+
+ // will have a 36 switch case at end to determine which image gets opened
+ int result = 0;
+
+ // 100 = NORTH, 200 = WEST, 300 = SOUTH, 400 = EAST
+ switch (r) {
+ case 0 -> result += 100;
+ case 90 -> result += 400;
+ case 180 -> result += 300;
+ case 270 -> result += 200;
+ default -> {
+ System.out.println("ThermometerElementView: Invalid Rotation");
+ return null;
+ }
+ }
+
+ // 10 = EMPTY, 20 = FILLED, 30 = BLOCKED
+ switch (f) {
+ case ThermometerFill.EMPTY -> result += 10;
+ case ThermometerFill.FILLED -> result += 20;
+ case ThermometerFill.BLOCKED -> result += 30;
+ default -> {
+ System.out.println("ThermometerElementView: Invalid Fill");
+ return null;
+ }
+ }
+
+ // 1 = HEAD, 2 = SHAFT, 3 = TIP
+ switch (t) {
+ case ThermometerType.HEAD -> result += 1;
+ case ThermometerType.SHAFT -> result += 2;
+ case ThermometerType.TIP -> result += 3;
+ default -> {
+ System.out.println("ThermometerElementView: Invalid Type");
+ return null;
+ }
+ }
+
+ try {
+ switch (result) {
+ case 111 -> {
+ return ImageIO.read(
+ ClassLoader.getSystemResourceAsStream(
+ "edu/rpi/legup/images/thermometer/Elements/HeadEmpN.png"));
+ }
+
+ case 112 -> {
+ return ImageIO.read(
+ ClassLoader.getSystemResourceAsStream(
+ "edu/rpi/legup/images/thermometer/Elements/ShaftEmpN.png"));
+ }
+
+ case 113 -> {
+ return ImageIO.read(
+ ClassLoader.getSystemResourceAsStream(
+ "edu/rpi/legup/images/thermometer/Elements/TipEmpN.png"));
+ }
+
+ case 121 -> {
+ return ImageIO.read(
+ ClassLoader.getSystemResourceAsStream(
+ "edu/rpi/legup/images/thermometer/Elements/HeadFillN.png"));
+ }
+
+ case 122 -> {
+ return ImageIO.read(
+ ClassLoader.getSystemResourceAsStream(
+ "edu/rpi/legup/images/thermometer/Elements/ShaftFillN.png"));
+ }
+
+ case 123 -> {
+ return ImageIO.read(
+ ClassLoader.getSystemResourceAsStream(
+ "edu/rpi/legup/images/thermometer/Elements/TipFillN.png"));
+ }
+
+ case 131 -> {
+ return ImageIO.read(
+ ClassLoader.getSystemResourceAsStream(
+ "edu/rpi/legup/images/thermometer/Elements/HeadBlockN.png"));
+ }
+
+ case 132 -> {
+ return ImageIO.read(
+ ClassLoader.getSystemResourceAsStream(
+ "edu/rpi/legup/images/thermometer/Elements/ShaftBlockN.png"));
+ }
+
+ case 133 -> {
+ return ImageIO.read(
+ ClassLoader.getSystemResourceAsStream(
+ "edu/rpi/legup/images/thermometer/Elements/TipBlockN.png"));
+ }
+
+ case 211 -> {
+ return ImageIO.read(
+ ClassLoader.getSystemResourceAsStream(
+ "edu/rpi/legup/images/thermometer/Elements/HeadEmpE.png"));
+ }
+
+ case 212 -> {
+ return ImageIO.read(
+ ClassLoader.getSystemResourceAsStream(
+ "edu/rpi/legup/images/thermometer/Elements/ShaftEmpE.png"));
+ }
+
+ case 213 -> {
+ return ImageIO.read(
+ ClassLoader.getSystemResourceAsStream(
+ "edu/rpi/legup/images/thermometer/Elements/TipEmpE.png"));
+ }
+
+ case 221 -> {
+ return ImageIO.read(
+ ClassLoader.getSystemResourceAsStream(
+ "edu/rpi/legup/images/thermometer/Elements/HeadFillE.png"));
+ }
+
+ case 222 -> {
+ return ImageIO.read(
+ ClassLoader.getSystemResourceAsStream(
+ "edu/rpi/legup/images/thermometer/Elements/ShaftFillE.png"));
+ }
+
+ case 223 -> {
+ return ImageIO.read(
+ ClassLoader.getSystemResourceAsStream(
+ "edu/rpi/legup/images/thermometer/Elements/TipFillE.png"));
+ }
+
+ case 231 -> {
+ return ImageIO.read(
+ ClassLoader.getSystemResourceAsStream(
+ "edu/rpi/legup/images/thermometer/Elements/HeadBlockE.png"));
+ }
+
+ case 232 -> {
+ return ImageIO.read(
+ ClassLoader.getSystemResourceAsStream(
+ "edu/rpi/legup/images/thermometer/Elements/ShaftBlockE.png"));
+ }
+
+ case 233 -> {
+ return ImageIO.read(
+ ClassLoader.getSystemResourceAsStream(
+ "edu/rpi/legup/images/thermometer/Elements/TipBlockE.png"));
+ }
+
+ case 311 -> {
+ return ImageIO.read(
+ ClassLoader.getSystemResourceAsStream(
+ "edu/rpi/legup/images/thermometer/Elements/HeadEmpS.png"));
+ }
+
+ case 312 -> {
+ return ImageIO.read(
+ ClassLoader.getSystemResourceAsStream(
+ "edu/rpi/legup/images/thermometer/Elements/ShaftEmpS.png"));
+ }
+
+ case 313 -> {
+ return ImageIO.read(
+ ClassLoader.getSystemResourceAsStream(
+ "edu/rpi/legup/images/thermometer/Elements/TipEmpS.png"));
+ }
+
+ case 321 -> {
+ return ImageIO.read(
+ ClassLoader.getSystemResourceAsStream(
+ "edu/rpi/legup/images/thermometer/Elements/HeadFillS.png"));
+ }
+
+ case 322 -> {
+ return ImageIO.read(
+ ClassLoader.getSystemResourceAsStream(
+ "edu/rpi/legup/images/thermometer/Elements/ShaftFillS.png"));
+ }
+
+ case 323 -> {
+ return ImageIO.read(
+ ClassLoader.getSystemResourceAsStream(
+ "edu/rpi/legup/images/thermometer/Elements/TipFillS.png"));
+ }
+
+ case 331 -> {
+ return ImageIO.read(
+ ClassLoader.getSystemResourceAsStream(
+ "edu/rpi/legup/images/thermometer/Elements/HeadBlockS.png"));
+ }
+
+ case 332 -> {
+ return ImageIO.read(
+ ClassLoader.getSystemResourceAsStream(
+ "edu/rpi/legup/images/thermometer/Elements/ShaftBlockS.png"));
+ }
+
+ case 333 -> {
+ return ImageIO.read(
+ ClassLoader.getSystemResourceAsStream(
+ "edu/rpi/legup/images/thermometer/Elements/TipBlockS.png"));
+ }
+
+ case 411 -> {
+ return ImageIO.read(
+ ClassLoader.getSystemResourceAsStream(
+ "edu/rpi/legup/images/thermometer/Elements/HeadEmpW.png"));
+ }
+
+ case 412 -> {
+ return ImageIO.read(
+ ClassLoader.getSystemResourceAsStream(
+ "edu/rpi/legup/images/thermometer/Elements/ShaftEmpW.png"));
+ }
+
+ case 413 -> {
+ return ImageIO.read(
+ ClassLoader.getSystemResourceAsStream(
+ "edu/rpi/legup/images/thermometer/Elements/TipEmpW.png"));
+ }
+
+ case 421 -> {
+ return ImageIO.read(
+ ClassLoader.getSystemResourceAsStream(
+ "edu/rpi/legup/images/thermometer/Elements/HeadFillW.png"));
+ }
+
+ case 422 -> {
+ return ImageIO.read(
+ ClassLoader.getSystemResourceAsStream(
+ "edu/rpi/legup/images/thermometer/Elements/ShaftFillW.png"));
+ }
+
+ case 423 -> {
+ return ImageIO.read(
+ ClassLoader.getSystemResourceAsStream(
+ "edu/rpi/legup/images/thermometer/Elements/TipFillW.png"));
+ }
+
+ case 431 -> {
+ return ImageIO.read(
+ ClassLoader.getSystemResourceAsStream(
+ "edu/rpi/legup/images/thermometer/Elements/HeadBlockW.png"));
+ }
+
+ case 432 -> {
+ return ImageIO.read(
+ ClassLoader.getSystemResourceAsStream(
+ "edu/rpi/legup/images/thermometer/Elements/ShaftBlockW.png"));
+ }
+
+ case 433 -> {
+ return ImageIO.read(
+ ClassLoader.getSystemResourceAsStream(
+ "edu/rpi/legup/images/thermometer/Elements/TipBlockW.png"));
+ }
+ }
+ } catch (IOException e) {
+ System.out.println("ThermometerElementView: Unexpected Issue");
+ return null;
+ }
+
+ return null;
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerExporter.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerExporter.java
new file mode 100644
index 000000000..d4e6dbd39
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerExporter.java
@@ -0,0 +1,72 @@
+package edu.rpi.legup.puzzle.thermometer;
+
+import edu.rpi.legup.model.PuzzleExporter;
+import java.util.ArrayList;
+import org.w3c.dom.Document;
+
+public class ThermometerExporter extends PuzzleExporter {
+
+ public ThermometerExporter(Thermometer thermometer) {
+ super(thermometer);
+ }
+
+ @Override
+ protected org.w3c.dom.Element createBoardElement(Document newDocument) {
+ ThermometerBoard board = (ThermometerBoard) puzzle.getTree().getRootNode().getBoard();
+
+ // Creating the XML section for the board
+ org.w3c.dom.Element boardElement = newDocument.createElement("board");
+ boardElement.setAttribute("width", String.valueOf(board.getWidth() - 1));
+ boardElement.setAttribute("height", String.valueOf(board.getHeight() - 1));
+
+ // Creating the XML section for the vials and appending to the board
+ org.w3c.dom.Element vialsElement = newDocument.createElement("vials");
+ ArrayList vials = board.getVials();
+ for (ThermometerVial vial : vials) {
+ org.w3c.dom.Element vialElement = newDocument.createElement("vial");
+ // The way the vials are created are with the head (bulb) position and the final
+ // position
+ // This implementation doesn't allow for curved thermometers, but for right now that's
+ // fine
+ vialElement.setAttribute(
+ "headx", String.valueOf((int) vial.getHead().getLocation().getX()));
+ vialElement.setAttribute(
+ "heady", String.valueOf((int) vial.getHead().getLocation().getY()));
+ vialElement.setAttribute(
+ "tailx", String.valueOf((int) vial.getTail().getLocation().getX()));
+ vialElement.setAttribute(
+ "taily", String.valueOf((int) vial.getTail().getLocation().getY()));
+ vialsElement.appendChild(vialElement);
+ }
+ boardElement.appendChild(vialsElement);
+
+ // Creating the XML section for the row numbers and appending to the board
+ org.w3c.dom.Element rowNumbersElement = newDocument.createElement("rowNumbers");
+ ArrayList rowNumbers = board.getRowNumbers();
+ // The row numbers are the numbers on the right most column, labeling how many filled
+ // sections
+ // are in the row
+ for (ThermometerCell cell : rowNumbers) {
+ int number = cell.getRotation();
+ org.w3c.dom.Element rowNumberElement = newDocument.createElement("row");
+ rowNumberElement.setAttribute("value", String.valueOf(number));
+ rowNumbersElement.appendChild(rowNumberElement);
+ }
+ boardElement.appendChild(rowNumbersElement);
+
+ // Creating the XML section for the col numbers and appending ot the board
+ org.w3c.dom.Element colNumbersElement = newDocument.createElement("colNumbers");
+ // The col numbers are the numbers on the bottom row, labeling how many filled sections
+ // are in the column
+ ArrayList colNumbers = board.getColNumbers();
+ for (ThermometerCell cell : colNumbers) {
+ int number = cell.getRotation();
+ org.w3c.dom.Element colNumberElement = newDocument.createElement("col");
+ colNumberElement.setAttribute("value", String.valueOf(number));
+ colNumbersElement.appendChild(colNumberElement);
+ }
+ boardElement.appendChild(colNumbersElement);
+
+ return boardElement;
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerFill.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerFill.java
new file mode 100644
index 000000000..34a1ff12e
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerFill.java
@@ -0,0 +1,8 @@
+package edu.rpi.legup.puzzle.thermometer;
+
+public enum ThermometerFill {
+ UNKNOWN,
+ EMPTY,
+ FILLED,
+ BLOCKED;
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerImporter.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerImporter.java
new file mode 100644
index 000000000..711418d63
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerImporter.java
@@ -0,0 +1,196 @@
+package edu.rpi.legup.puzzle.thermometer;
+
+import static java.lang.Math.max;
+import static java.lang.Math.min;
+
+import edu.rpi.legup.model.PuzzleImporter;
+import edu.rpi.legup.save.InvalidFileFormatException;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+public class ThermometerImporter extends PuzzleImporter {
+
+ // basic stuff stolen from dev guide/filled in by default
+ public ThermometerImporter(Thermometer thermometer) {
+ super(thermometer);
+ }
+
+ @Override
+ public boolean acceptsRowsAndColumnsInput() {
+ return false;
+ }
+
+ @Override
+ public boolean acceptsTextInput() {
+ return false;
+ }
+
+ @Override
+ public void initializeBoard(int rows, int columns) {}
+
+ // method for initializing board from an xml file which has
+ // a provided width/height
+ @Override
+ public void initializeBoard(Node node) throws InvalidFileFormatException {
+ // sticking everything in a try statement because god has forsaken everyone
+ try {
+ // checking basic formatting of file
+ if (!node.getNodeName().equalsIgnoreCase("board")) {
+ throw new InvalidFileFormatException(
+ "thermometer Importer: cannot find board puzzleElement");
+ }
+
+ // getting the list of vials to turn into real vials
+ Element boardElement = (Element) node;
+ if (boardElement.getElementsByTagName("vials").getLength() == 0) {
+ throw new InvalidFileFormatException(
+ "thermometer Importer: no puzzleElement found for board");
+ }
+ Element dataElement = (Element) boardElement.getElementsByTagName("vials").item(0);
+ NodeList elementDataList = dataElement.getElementsByTagName("vial");
+
+ // checking both a width and height were provided for the board
+ ThermometerBoard thermometerBoard = null;
+ if (!boardElement.getAttribute("width").isEmpty()
+ && !boardElement.getAttribute("height").isEmpty()) {
+
+ // grabbing the height/width of the board
+ int width = Integer.parseInt(boardElement.getAttribute("width"));
+ int height = Integer.parseInt(boardElement.getAttribute("height"));
+
+ // grabbing the lists of rowNumbers/colNumbers
+ Element rowElement =
+ (Element) boardElement.getElementsByTagName("rowNumbers").item(0);
+ NodeList rowNodeList = rowElement.getElementsByTagName("row");
+
+ Element colElement =
+ (Element) boardElement.getElementsByTagName("colNumbers").item(0);
+ NodeList colNodeList = colElement.getElementsByTagName("col");
+
+ // checking that the number of row and col numbers agrees with height/width of board
+ if (colNodeList.getLength() != width) {
+ throw new InvalidFileFormatException(
+ "Mismatch between width and number of colNums.\n colNodeList.length:"
+ + colNodeList.getLength()
+ + " width:"
+ + width);
+ }
+ if (rowNodeList.getLength() != height) {
+ throw new InvalidFileFormatException(
+ "thermometer Importer: no rowNumbers found for board");
+ }
+
+ // finally creating our thermometer board, we add one to the size since row/col
+ // numbers
+ // are considered cells on the grid
+ thermometerBoard = new ThermometerBoard(width + 1, height + 1);
+ // adding row and column numbers to our board
+ importRowColNums(rowNodeList, colNodeList, thermometerBoard);
+ } else {
+ throw new InvalidFileFormatException(
+ "thermometer Importer: invalid board height/width");
+ }
+
+ // grabbing height/width from board, need to subtract 1
+ // because grids height/width is 1 bigger than number of vials on board
+ int width = thermometerBoard.getWidth() - 1;
+ int height = thermometerBoard.getHeight() - 1;
+
+ // adding in the vials
+ for (int i = 0; i < elementDataList.getLength(); i++) {
+ importThermometerVial(elementDataList.item(i), thermometerBoard);
+ }
+
+ // verifying all vial cells were filled by vials
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ if (thermometerBoard.getCell(x, y) == null) {
+ throw new InvalidFileFormatException(
+ "Thermometer importer Undefined tile at (" + x + "," + y + ")");
+ }
+ }
+ }
+
+ puzzle.setCurrentBoard(thermometerBoard);
+ } catch (NumberFormatException e) {
+ throw new InvalidFileFormatException(
+ "thermometer Importer: unknown value where integer expected");
+ }
+ }
+
+ @Override
+ public void initializeBoard(String[] statements)
+ throws UnsupportedOperationException, IllegalArgumentException {}
+
+ private void importRowColNums(NodeList rowNodes, NodeList colNodes, ThermometerBoard board)
+ throws InvalidFileFormatException {
+
+ // going through our list or row nodes grabbed from the xml file and
+ // then calling the thermometer boards setRowNumber function to update the value
+ for (int i = 0; i < rowNodes.getLength(); i++) {
+ Node node = rowNodes.item(i);
+ int rowNum =
+ Integer.parseInt(node.getAttributes().getNamedItem("value").getNodeValue());
+ if (!board.setRowNumber(i, rowNum)) {
+ throw new InvalidFileFormatException("thermometer Importer: out of bounds rowNum");
+ }
+ }
+
+ // same process but for col numbers
+ for (int i = 0; i < colNodes.getLength(); i++) {
+ Node node = colNodes.item(i);
+ int colNum =
+ Integer.parseInt(node.getAttributes().getNamedItem("value").getNodeValue());
+ if (!board.setColNumber(i, colNum)) {
+ throw new InvalidFileFormatException("thermometer Importer: out of bounds colNum");
+ }
+ }
+ }
+
+ private void importThermometerVial(Node node, ThermometerBoard board)
+ throws InvalidFileFormatException {
+ // head is the top of the thermometer and tip is the end of the thermometer
+ // thermometers in the xml are specified only by their head and tip cells
+ int headX = Integer.parseInt(node.getAttributes().getNamedItem("headx").getNodeValue());
+ int headY = Integer.parseInt(node.getAttributes().getNamedItem("heady").getNodeValue());
+ int tipX = Integer.parseInt(node.getAttributes().getNamedItem("tailx").getNodeValue());
+ int tipY = Integer.parseInt(node.getAttributes().getNamedItem("taily").getNodeValue());
+
+ // making sure we can add the vial before doing so
+ if (verifyVial(headX, headY, tipX, tipY, board)) {
+ // adding the vial to the board
+ board.addVial(new ThermometerVial(headX, headY, tipX, tipY, board));
+ } else {
+ throw new InvalidFileFormatException("thermometer Vial Factory: overlapping vials");
+ }
+ }
+
+ private boolean verifyVial(int headX, int headY, int tipX, int tipY, ThermometerBoard board) {
+ // figuring out which axis the thermometer travels along
+ if (headX == tipX) {
+ // finding start and end of Vial
+ int top = min(headY, tipY);
+ int bottom = max(headY, tipY);
+
+ // verifying that every cell along path is currently unconstructed
+ for (int i = top; i <= bottom; i++) {
+ if (board.getCell(headX, i) != null) return false;
+ }
+ } else if (headY == tipY) {
+ // finding start and end of Vial
+ // I have words to say to james
+ int left = min(headX, tipX);
+ int right = max(headX, tipX);
+
+ // verifying that every cell along path is currently unconstructed
+ for (int i = left; i <= right; i++) {
+ if (board.getCell(i, headY) != null) return false;
+ }
+ } else {
+ // thermometer does not line up along a single axis
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerNumberView.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerNumberView.java
new file mode 100644
index 000000000..4a00b8a18
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerNumberView.java
@@ -0,0 +1,37 @@
+package edu.rpi.legup.puzzle.thermometer;
+
+import edu.rpi.legup.model.gameboard.GridCell;
+import edu.rpi.legup.ui.boardview.GridElementView;
+import java.awt.*;
+
+public class ThermometerNumberView extends GridElementView {
+ private static final Font FONT = new Font("TimesRoman", Font.BOLD, 16);
+ private static final Color FONT_COLOR = Color.BLACK;
+
+ public ThermometerNumberView(GridCell cell) {
+ super(cell);
+ }
+
+ @Override
+ public GridCell getPuzzleElement() {
+ return (GridCell) super.getPuzzleElement();
+ }
+
+ @Override
+ public void drawElement(Graphics2D graphics2D) {
+ ThermometerCell cell = (ThermometerCell) puzzleElement;
+
+ graphics2D.setColor(FONT_COLOR);
+ graphics2D.setFont(FONT);
+ FontMetrics metrics = graphics2D.getFontMetrics(FONT);
+ int val;
+
+ if (cell != null) val = cell.getRotation();
+ else val = -1;
+
+ int xText = location.x + (size.width - metrics.stringWidth(String.valueOf(val))) / 2;
+ int yText = location.y + ((size.height - metrics.getHeight()) / 2) + metrics.getAscent();
+
+ graphics2D.drawString(String.valueOf(val), xText, yText);
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerType.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerType.java
new file mode 100644
index 000000000..f482411a5
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerType.java
@@ -0,0 +1,8 @@
+package edu.rpi.legup.puzzle.thermometer;
+
+public enum ThermometerType {
+ UNKNOWN,
+ HEAD,
+ SHAFT,
+ TIP;
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerVial.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerVial.java
new file mode 100644
index 000000000..2cba64363
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerVial.java
@@ -0,0 +1,103 @@
+package edu.rpi.legup.puzzle.thermometer;
+
+import java.awt.*;
+import java.util.ArrayList;
+
+public class ThermometerVial {
+ private ArrayList cells;
+
+ public ThermometerVial(int headX, int headY, int tipX, int tipY, ThermometerBoard board) {
+ // basic constructor, instantiating our members field and then
+ // calling helper function to do all the heavy lifting
+ cells = new ArrayList();
+ fillData(headX, headY, tipX, tipY, board);
+ }
+
+ // function called by the constructor which adds in all of the cells to the array
+ // as well as updates their type on the board
+ private void fillData(int headX, int headY, int tipX, int tipY, ThermometerBoard board) {
+ // not totally happy with layout of code but most readable version I can think of atm
+ // top left coordinate is 0,0 cells are added from head to tip always
+ // because cells have already been verified by time constructor is called
+ // we can guarantee that only the x or only the y coordinates wont line up
+ if (headY < tipY) {
+ addCell(headX, headY, ThermometerType.HEAD, 0, board);
+ for (int i = headY + 1; i < tipY; i++) {
+ addCell(headX, i, ThermometerType.SHAFT, 0, board);
+ }
+ addCell(tipX, tipY, ThermometerType.TIP, 0, board);
+ } else if (tipY < headY) {
+ addCell(headX, headY, ThermometerType.HEAD, 180, board);
+ for (int i = headY - 1; i > tipY; i--) {
+ addCell(headX, i, ThermometerType.SHAFT, 180, board);
+ }
+ addCell(tipX, tipY, ThermometerType.TIP, 180, board);
+ } else if (headX < tipX) {
+ addCell(headX, headY, ThermometerType.HEAD, 90, board);
+ for (int i = headX + 1; i < tipX; i++) {
+ addCell(i, headY, ThermometerType.SHAFT, 90, board);
+ }
+ addCell(tipX, tipY, ThermometerType.TIP, 90, board);
+ } else {
+ addCell(headX, headY, ThermometerType.HEAD, 270, board);
+ for (int i = headX - 1; i > tipX; i--) {
+ addCell(i, headY, ThermometerType.SHAFT, 270, board);
+ }
+ addCell(tipX, tipY, ThermometerType.TIP, 270, board);
+ }
+ }
+
+ // helper function for adding a single cell
+ private void addCell(int x, int y, ThermometerType t, int rotation, ThermometerBoard board) {
+ ThermometerCell cell =
+ new ThermometerCell(new Point(x, y), t, ThermometerFill.EMPTY, rotation);
+ cell.setIndex(y * board.getHeight() + x);
+ this.cells.add(cell);
+ // still important for element view stuff
+ board.setCell(x, y, cell);
+ }
+
+ // TODO (probably) DOES NOT WORK AS INTENDED
+ // BECAUSE MOST RULES GET A PUZZLE ELEMENT PASSED IN AND WEIRD
+ // TYPE CASTING STUFF, PAY ATTENTION TO THIS WHEN WE START
+ // DEBUGGING RULES
+ // a basic accessor to check if a cell is contained in vial
+ public boolean containsCell(ThermometerCell cell) {
+ for (ThermometerCell c : cells) {
+ if (c.getLocation() == cell.getLocation()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // Returns cell containing head of thermometer
+ public ThermometerCell getHead() {
+ return cells.getFirst();
+ }
+
+ // Returns cell containing tail of thermometer
+ public ThermometerCell getTail() {
+ return cells.getLast();
+ }
+
+ // Retruns all cells in vial, from head to tip
+ public ArrayList getCells() {
+ return cells;
+ }
+
+ // checking for discontinuous flow inside of vial
+ public boolean continuousFlow() {
+ // bool which is true until it runs into an empty/blocked cell in the vial
+ // if an empty cell in the vial is found while flow is set to false
+ // we know there is a break in the flow
+ boolean flow = true;
+
+ for (ThermometerCell c : cells) {
+ if (c.getFill() != ThermometerFill.FILLED && flow) flow = false;
+
+ if (c.getFill() == ThermometerFill.FILLED && !flow) return false;
+ }
+ return true;
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerView.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerView.java
new file mode 100644
index 000000000..444037cfe
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerView.java
@@ -0,0 +1,48 @@
+package edu.rpi.legup.puzzle.thermometer;
+
+import edu.rpi.legup.controller.BoardController;
+import edu.rpi.legup.ui.boardview.GridBoardView;
+import java.awt.*;
+
+public class ThermometerView extends GridBoardView {
+
+ public ThermometerView(ThermometerBoard board) {
+ super(new BoardController(), new ThermometerController(), board.getDimension());
+
+ // loop for displaying the vial cells
+ // stolen largely from dev guide
+ for (ThermometerVial vial : board.getVials()) {
+ for (ThermometerCell cell : vial.getCells()) {
+ Point loc = cell.getLocation();
+ ThermometerElementView elementView = new ThermometerElementView(cell);
+ elementView.setIndex(cell.getIndex());
+ elementView.setSize(elementSize);
+ elementView.setLocation(
+ new Point(loc.x * elementSize.width, loc.y * elementSize.height));
+ elementViews.add(elementView);
+ }
+ }
+
+ // loop for displaying row numbers, same as above
+ for (ThermometerCell rowNum : board.getRowNumbers()) {
+ Point loc = rowNum.getLocation();
+ ThermometerNumberView numberView = new ThermometerNumberView(rowNum);
+ numberView.setIndex(rowNum.getIndex());
+ numberView.setSize(elementSize);
+ numberView.setLocation(
+ new Point(loc.x * elementSize.width, loc.y * elementSize.height));
+ elementViews.add(numberView);
+ }
+
+ // loop for displaying col numbers, also same as above
+ for (ThermometerCell colNum : board.getColNumbers()) {
+ Point loc = colNum.getLocation();
+ ThermometerNumberView numberView = new ThermometerNumberView(colNum);
+ numberView.setIndex(colNum.getIndex());
+ numberView.setSize(elementSize);
+ numberView.setLocation(
+ new Point(loc.x * elementSize.width, loc.y * elementSize.height));
+ elementViews.add(numberView);
+ }
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileBlckE.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileBlckE.java
new file mode 100644
index 000000000..8f0507ab5
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileBlckE.java
@@ -0,0 +1,13 @@
+package edu.rpi.legup.puzzle.thermometer.elements;
+
+import edu.rpi.legup.model.elements.PlaceableElement;
+
+public class HeadTileBlckE extends PlaceableElement {
+ public HeadTileBlckE() {
+ super(
+ "Therm-PLAC-0001",
+ "Head Tile Block East",
+ "The tile corresponding to the blocked head of an east thermometer",
+ "edu/rpi/legup/images/thermometer/Elements/HeadBlockE.png");
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileBlckN.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileBlckN.java
new file mode 100644
index 000000000..f195c299b
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileBlckN.java
@@ -0,0 +1,13 @@
+package edu.rpi.legup.puzzle.thermometer.elements;
+
+import edu.rpi.legup.model.elements.PlaceableElement;
+
+public class HeadTileBlckN extends PlaceableElement {
+ public HeadTileBlckN() {
+ super(
+ "Therm-PLAC-0002",
+ "Head Tile Block North",
+ "The tile corresponding to the blocked head of a north thermometer",
+ "edu/rpi/legup/images/thermometer/Elements/HeadBlockN.png");
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileBlckS.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileBlckS.java
new file mode 100644
index 000000000..d9e4c4a6a
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileBlckS.java
@@ -0,0 +1,13 @@
+package edu.rpi.legup.puzzle.thermometer.elements;
+
+import edu.rpi.legup.model.elements.PlaceableElement;
+
+public class HeadTileBlckS extends PlaceableElement {
+ public HeadTileBlckS() {
+ super(
+ "Therm-PLAC-0003",
+ "Head Tile Block South",
+ "The tile corresponding to the blocked head of a south thermometer",
+ "edu/rpi/legup/images/thermometer/Elements/HeadBlockS.png");
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileBlckW.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileBlckW.java
new file mode 100644
index 000000000..2bcbfdf2d
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileBlckW.java
@@ -0,0 +1,13 @@
+package edu.rpi.legup.puzzle.thermometer.elements;
+
+import edu.rpi.legup.model.elements.PlaceableElement;
+
+public class HeadTileBlckW extends PlaceableElement {
+ public HeadTileBlckW() {
+ super(
+ "Therm-PLAC-0004",
+ "Head Tile Block West",
+ "The tile corresponding to the blocked head of a west thermometer",
+ "edu/rpi/legup/images/thermometer/Elements/HeadBlockW.png");
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileEmpE.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileEmpE.java
new file mode 100644
index 000000000..0b678ed73
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileEmpE.java
@@ -0,0 +1,13 @@
+package edu.rpi.legup.puzzle.thermometer.elements;
+
+import edu.rpi.legup.model.elements.PlaceableElement;
+
+public class HeadTileEmpE extends PlaceableElement {
+ public HeadTileEmpE() {
+ super(
+ "Therm-PLAC-0005",
+ "Head Tile Empty East",
+ "The tile corresponding to the empty head of an east thermometer",
+ "edu/rpi/legup/images/thermometer/Elements/HeadEmpE.png");
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileEmpN.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileEmpN.java
new file mode 100644
index 000000000..b865b0cae
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileEmpN.java
@@ -0,0 +1,13 @@
+package edu.rpi.legup.puzzle.thermometer.elements;
+
+import edu.rpi.legup.model.elements.PlaceableElement;
+
+public class HeadTileEmpN extends PlaceableElement {
+ public HeadTileEmpN() {
+ super(
+ "Therm-PLAC-0006",
+ "Head Tile Empty North",
+ "The tile corresponding to the empty head of a North thermometer",
+ "edu/rpi/legup/images/thermometer/Elements/HeadEmpN.png");
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileEmpS.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileEmpS.java
new file mode 100644
index 000000000..40989d814
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileEmpS.java
@@ -0,0 +1,13 @@
+package edu.rpi.legup.puzzle.thermometer.elements;
+
+import edu.rpi.legup.model.elements.PlaceableElement;
+
+public class HeadTileEmpS extends PlaceableElement {
+ public HeadTileEmpS() {
+ super(
+ "Therm-PLAC-0007",
+ "Head Tile Empty South",
+ "The tile corresponding to the empty head of a south thermometer",
+ "edu/rpi/legup/images/thermometer/Elements/HeadEmpS.png");
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileEmpW.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileEmpW.java
new file mode 100644
index 000000000..ba344ff8a
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileEmpW.java
@@ -0,0 +1,13 @@
+package edu.rpi.legup.puzzle.thermometer.elements;
+
+import edu.rpi.legup.model.elements.PlaceableElement;
+
+public class HeadTileEmpW extends PlaceableElement {
+ public HeadTileEmpW() {
+ super(
+ "Therm-PLAC-0008",
+ "Head Tile Empty West",
+ "The tile corresponding to the empty head of a west thermometer",
+ "edu/rpi/legup/images/thermometer/Elements/HeadEmpW.png");
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileFillE.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileFillE.java
new file mode 100644
index 000000000..e8bfb8f82
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileFillE.java
@@ -0,0 +1,13 @@
+package edu.rpi.legup.puzzle.thermometer.elements;
+
+import edu.rpi.legup.model.elements.PlaceableElement;
+
+public class HeadTileFillE extends PlaceableElement {
+ public HeadTileFillE() {
+ super(
+ "Therm-PLAC-0009",
+ "Head Tile Filled East",
+ "The tile corresponding to the filled head of an east thermometer",
+ "edu/rpi/legup/images/thermometer/Elements/HeadFillE.png");
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileFillN.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileFillN.java
new file mode 100644
index 000000000..4a835601c
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileFillN.java
@@ -0,0 +1,13 @@
+package edu.rpi.legup.puzzle.thermometer.elements;
+
+import edu.rpi.legup.model.elements.PlaceableElement;
+
+public class HeadTileFillN extends PlaceableElement {
+ public HeadTileFillN() {
+ super(
+ "Therm-PLAC-0010",
+ "Head Tile Filled North",
+ "The tile corresponding to the filled head of a north thermometer",
+ "edu/rpi/legup/images/thermometer/Elements/HeadFillN.png");
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileFillS.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileFillS.java
new file mode 100644
index 000000000..df559ec6f
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileFillS.java
@@ -0,0 +1,13 @@
+package edu.rpi.legup.puzzle.thermometer.elements;
+
+import edu.rpi.legup.model.elements.PlaceableElement;
+
+public class HeadTileFillS extends PlaceableElement {
+ public HeadTileFillS() {
+ super(
+ "Therm-PLAC-0011",
+ "Head Tile Filled South",
+ "The tile corresponding to the filled head of a south thermometer",
+ "edu/rpi/legup/images/thermometer/Elements/HeadFillS.png");
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileFillW.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileFillW.java
new file mode 100644
index 000000000..80194ceaf
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileFillW.java
@@ -0,0 +1,13 @@
+package edu.rpi.legup.puzzle.thermometer.elements;
+
+import edu.rpi.legup.model.elements.PlaceableElement;
+
+public class HeadTileFillW extends PlaceableElement {
+ public HeadTileFillW() {
+ super(
+ "Therm-PLAC-0012",
+ "Head Tile Filled West",
+ "The tile corresponding to the filled head of a west thermometer",
+ "edu/rpi/legup/images/thermometer/Elements/HeadFillW.png");
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileBlckE.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileBlckE.java
new file mode 100644
index 000000000..7080b9a47
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileBlckE.java
@@ -0,0 +1,13 @@
+package edu.rpi.legup.puzzle.thermometer.elements;
+
+import edu.rpi.legup.model.elements.PlaceableElement;
+
+public class ShaftTileBlckE extends PlaceableElement {
+ public ShaftTileBlckE() {
+ super(
+ "Therm-PLAC-0013",
+ "Shaft Tile Blocked East",
+ "The tile corresponding to a Blocked middle segment of an east thermometer",
+ "edu/rpi/legup/images/thermometer/Elements/ShaftBlockE.png");
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileBlckN.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileBlckN.java
new file mode 100644
index 000000000..760baf624
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileBlckN.java
@@ -0,0 +1,13 @@
+package edu.rpi.legup.puzzle.thermometer.elements;
+
+import edu.rpi.legup.model.elements.PlaceableElement;
+
+public class ShaftTileBlckN extends PlaceableElement {
+ public ShaftTileBlckN() {
+ super(
+ "Therm-PLAC-0014",
+ "Shaft Tile Blocked North",
+ "The tile corresponding to a Blocked middle segment of a north thermometer",
+ "edu/rpi/legup/images/thermometer/Elements/ShaftBlockN.png");
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileBlckS.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileBlckS.java
new file mode 100644
index 000000000..ec14a669d
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileBlckS.java
@@ -0,0 +1,13 @@
+package edu.rpi.legup.puzzle.thermometer.elements;
+
+import edu.rpi.legup.model.elements.PlaceableElement;
+
+public class ShaftTileBlckS extends PlaceableElement {
+ public ShaftTileBlckS() {
+ super(
+ "Therm-PLAC-0015",
+ "Shaft Tile Blocked South",
+ "The tile corresponding to a Blocked middle segment of a south thermometer",
+ "edu/rpi/legup/images/thermometer/Elements/ShaftBlockS.png");
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileBlckW.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileBlckW.java
new file mode 100644
index 000000000..183fd798c
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileBlckW.java
@@ -0,0 +1,13 @@
+package edu.rpi.legup.puzzle.thermometer.elements;
+
+import edu.rpi.legup.model.elements.PlaceableElement;
+
+public class ShaftTileBlckW extends PlaceableElement {
+ public ShaftTileBlckW() {
+ super(
+ "Therm-PLAC-0016",
+ "Shaft Tile Blocked West",
+ "The tile corresponding to a Blocked middle segment of a west thermometer",
+ "edu/rpi/legup/images/thermometer/Elements/ShaftBlockW.png");
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileEmpE.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileEmpE.java
new file mode 100644
index 000000000..771c1afc3
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileEmpE.java
@@ -0,0 +1,13 @@
+package edu.rpi.legup.puzzle.thermometer.elements;
+
+import edu.rpi.legup.model.elements.PlaceableElement;
+
+public class ShaftTileEmpE extends PlaceableElement {
+ public ShaftTileEmpE() {
+ super(
+ "Therm-PLAC-0017",
+ "Shaft Tile Empty East",
+ "The tile corresponding to an empty middle segment of an east thermometer",
+ "edu/rpi/legup/images/thermometer/Elements/ShaftEmpE.png");
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileEmpN.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileEmpN.java
new file mode 100644
index 000000000..c2ec4e0ab
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileEmpN.java
@@ -0,0 +1,13 @@
+package edu.rpi.legup.puzzle.thermometer.elements;
+
+import edu.rpi.legup.model.elements.PlaceableElement;
+
+public class ShaftTileEmpN extends PlaceableElement {
+ public ShaftTileEmpN() {
+ super(
+ "Therm-PLAC-0018",
+ "Shaft Tile Empty North",
+ "The tile corresponding to an empty middle segment of a north thermometer",
+ "edu/rpi/legup/images/thermometer/Elements/ShaftEmpN.png");
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileEmpS.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileEmpS.java
new file mode 100644
index 000000000..fc2828ddb
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileEmpS.java
@@ -0,0 +1,13 @@
+package edu.rpi.legup.puzzle.thermometer.elements;
+
+import edu.rpi.legup.model.elements.PlaceableElement;
+
+public class ShaftTileEmpS extends PlaceableElement {
+ public ShaftTileEmpS() {
+ super(
+ "Therm-PLAC-0019",
+ "Shaft Tile Empty South",
+ "The tile corresponding to an empty middle segment of a south thermometer",
+ "edu/rpi/legup/images/thermometer/Elements/ShaftEmpS.png");
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileEmpW.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileEmpW.java
new file mode 100644
index 000000000..ce0e7bce3
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileEmpW.java
@@ -0,0 +1,13 @@
+package edu.rpi.legup.puzzle.thermometer.elements;
+
+import edu.rpi.legup.model.elements.PlaceableElement;
+
+public class ShaftTileEmpW extends PlaceableElement {
+ public ShaftTileEmpW() {
+ super(
+ "Therm-PLAC-0020",
+ "Shaft Tile Empty West",
+ "The tile corresponding to an empty middle segment of a west thermometer",
+ "edu/rpi/legup/images/thermometer/Elements/ShaftEmpW.png");
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileFillE.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileFillE.java
new file mode 100644
index 000000000..a8aeb44ed
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileFillE.java
@@ -0,0 +1,13 @@
+package edu.rpi.legup.puzzle.thermometer.elements;
+
+import edu.rpi.legup.model.elements.PlaceableElement;
+
+public class ShaftTileFillE extends PlaceableElement {
+ public ShaftTileFillE() {
+ super(
+ "Therm-PLAC-0021",
+ "Shaft Tile Filled East",
+ "The tile corresponding to a filled middle segment of an east thermometer",
+ "edu/rpi/legup/images/thermometer/Elements/ShaftFillE.png");
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileFillN.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileFillN.java
new file mode 100644
index 000000000..0366c3d0b
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileFillN.java
@@ -0,0 +1,13 @@
+package edu.rpi.legup.puzzle.thermometer.elements;
+
+import edu.rpi.legup.model.elements.PlaceableElement;
+
+public class ShaftTileFillN extends PlaceableElement {
+ public ShaftTileFillN() {
+ super(
+ "Therm-PLAC-0022",
+ "Shaft Tile Filled North",
+ "The tile corresponding to a filled middle segment of a north thermometer",
+ "edu/rpi/legup/images/thermometer/Elements/ShaftFillN.png");
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileFillS.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileFillS.java
new file mode 100644
index 000000000..b55d2a1f9
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileFillS.java
@@ -0,0 +1,13 @@
+package edu.rpi.legup.puzzle.thermometer.elements;
+
+import edu.rpi.legup.model.elements.PlaceableElement;
+
+public class ShaftTileFillS extends PlaceableElement {
+ public ShaftTileFillS() {
+ super(
+ "Therm-PLAC-0023",
+ "Shaft Tile Filled South",
+ "The tile corresponding to a filled middle segment of a south thermometer",
+ "edu/rpi/legup/images/thermometer/Elements/ShaftFillS.png");
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileFillW.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileFillW.java
new file mode 100644
index 000000000..3b2cd0454
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileFillW.java
@@ -0,0 +1,13 @@
+package edu.rpi.legup.puzzle.thermometer.elements;
+
+import edu.rpi.legup.model.elements.PlaceableElement;
+
+public class ShaftTileFillW extends PlaceableElement {
+ public ShaftTileFillW() {
+ super(
+ "Therm-PLAC-0024",
+ "Shaft Tile Filled West",
+ "The tile corresponding to a filled middle segment of a west thermometer",
+ "edu/rpi/legup/images/thermometer/Elements/ShaftFillS.png");
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileBlckE.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileBlckE.java
new file mode 100644
index 000000000..ea94846c2
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileBlckE.java
@@ -0,0 +1,13 @@
+package edu.rpi.legup.puzzle.thermometer.elements;
+
+import edu.rpi.legup.model.elements.PlaceableElement;
+
+public class TipTileBlckE extends PlaceableElement {
+ public TipTileBlckE() {
+ super(
+ "Therm-PLAC-0025",
+ "Tip Tile Block East",
+ "The tile corresponding to the Blocked tip of an east thermometer",
+ "edu/rpi/legup/images/thermometer/Elements/TipBlockE.png");
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileBlckN.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileBlckN.java
new file mode 100644
index 000000000..25ae8afda
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileBlckN.java
@@ -0,0 +1,13 @@
+package edu.rpi.legup.puzzle.thermometer.elements;
+
+import edu.rpi.legup.model.elements.PlaceableElement;
+
+public class TipTileBlckN extends PlaceableElement {
+ public TipTileBlckN() {
+ super(
+ "Therm-PLAC-0026",
+ "Tip Tile Block North",
+ "The tile corresponding to the Blocked tip of a north thermometer",
+ "edu/rpi/legup/images/thermometer/Elements/TipBlockN.png");
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileBlckS.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileBlckS.java
new file mode 100644
index 000000000..e19082162
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileBlckS.java
@@ -0,0 +1,13 @@
+package edu.rpi.legup.puzzle.thermometer.elements;
+
+import edu.rpi.legup.model.elements.PlaceableElement;
+
+public class TipTileBlckS extends PlaceableElement {
+ public TipTileBlckS() {
+ super(
+ "Therm-PLAC-0027",
+ "Tip Tile Block South",
+ "The tile corresponding to the Blocked tip of a south thermometer",
+ "edu/rpi/legup/images/thermometer/Elements/TipBlockS.png");
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileBlckW.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileBlckW.java
new file mode 100644
index 000000000..a0c49bc77
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileBlckW.java
@@ -0,0 +1,13 @@
+package edu.rpi.legup.puzzle.thermometer.elements;
+
+import edu.rpi.legup.model.elements.PlaceableElement;
+
+public class TipTileBlckW extends PlaceableElement {
+ public TipTileBlckW() {
+ super(
+ "Therm-PLAC-0028",
+ "Tip Tile Block West",
+ "The tile corresponding to the Blocked tip of a west thermometer",
+ "edu/rpi/legup/images/thermometer/Elements/TipBlockW.png");
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileEmpE.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileEmpE.java
new file mode 100644
index 000000000..6595da855
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileEmpE.java
@@ -0,0 +1,13 @@
+package edu.rpi.legup.puzzle.thermometer.elements;
+
+import edu.rpi.legup.model.elements.PlaceableElement;
+
+public class TipTileEmpE extends PlaceableElement {
+ public TipTileEmpE() {
+ super(
+ "Therm-PLAC-0029",
+ "Tip Tile Empty East",
+ "The tile corresponding to the empty tip of an east thermometer",
+ "edu/rpi/legup/images/thermometer/Elements/TipEmpE.png");
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileEmpN.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileEmpN.java
new file mode 100644
index 000000000..cacfe5d5d
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileEmpN.java
@@ -0,0 +1,13 @@
+package edu.rpi.legup.puzzle.thermometer.elements;
+
+import edu.rpi.legup.model.elements.PlaceableElement;
+
+public class TipTileEmpN extends PlaceableElement {
+ public TipTileEmpN() {
+ super(
+ "Therm-PLAC-0030",
+ "Tip Tile Empty North",
+ "The tile corresponding to the empty tip of a north thermometer",
+ "edu/rpi/legup/images/thermometer/Elements/TipEmpN.png");
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileEmpS.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileEmpS.java
new file mode 100644
index 000000000..2815b9fa1
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileEmpS.java
@@ -0,0 +1,13 @@
+package edu.rpi.legup.puzzle.thermometer.elements;
+
+import edu.rpi.legup.model.elements.PlaceableElement;
+
+public class TipTileEmpS extends PlaceableElement {
+ public TipTileEmpS() {
+ super(
+ "Therm-PLAC-0031",
+ "Tip Tile Empty South",
+ "The tile corresponding to the empty tip of a south thermometer",
+ "edu/rpi/legup/images/thermometer/Elements/TipEmpS.png");
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileEmpW.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileEmpW.java
new file mode 100644
index 000000000..3bd77495f
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileEmpW.java
@@ -0,0 +1,13 @@
+package edu.rpi.legup.puzzle.thermometer.elements;
+
+import edu.rpi.legup.model.elements.PlaceableElement;
+
+public class TipTileEmpW extends PlaceableElement {
+ public TipTileEmpW() {
+ super(
+ "Therm-PLAC-0032",
+ "Tip Tile Empty West",
+ "The tile corresponding to the empty tip of a west thermometer",
+ "edu/rpi/legup/images/thermometer/Elements/TipEmpW.png");
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileFillE.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileFillE.java
new file mode 100644
index 000000000..8c9953dd2
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileFillE.java
@@ -0,0 +1,13 @@
+package edu.rpi.legup.puzzle.thermometer.elements;
+
+import edu.rpi.legup.model.elements.PlaceableElement;
+
+public class TipTileFillE extends PlaceableElement {
+ public TipTileFillE() {
+ super(
+ "Therm-PLAC-0033",
+ "Tip Tile Fill East",
+ "The tile corresponding to the filled tip of an east thermometer",
+ "edu/rpi/legup/images/thermometer/Elements/TipFillE.png");
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileFillN.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileFillN.java
new file mode 100644
index 000000000..f5ce01c7b
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileFillN.java
@@ -0,0 +1,13 @@
+package edu.rpi.legup.puzzle.thermometer.elements;
+
+import edu.rpi.legup.model.elements.PlaceableElement;
+
+public class TipTileFillN extends PlaceableElement {
+ public TipTileFillN() {
+ super(
+ "Therm-PLAC-0034",
+ "Tip Tile Fill North",
+ "The tile corresponding to the filled tip of a north thermometer",
+ "edu/rpi/legup/images/thermometer/Elements/TipFillN.png");
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileFillS.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileFillS.java
new file mode 100644
index 000000000..05d68fe81
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileFillS.java
@@ -0,0 +1,13 @@
+package edu.rpi.legup.puzzle.thermometer.elements;
+
+import edu.rpi.legup.model.elements.PlaceableElement;
+
+public class TipTileFillS extends PlaceableElement {
+ public TipTileFillS() {
+ super(
+ "Therm-PLAC-0035",
+ "Tip Tile Fill South",
+ "The tile corresponding to the filled tip of a south thermometer",
+ "edu/rpi/legup/images/thermometer/Elements/TipFillS.png");
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileFillW.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileFillW.java
new file mode 100644
index 000000000..6aa486ba1
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileFillW.java
@@ -0,0 +1,13 @@
+package edu.rpi.legup.puzzle.thermometer.elements;
+
+import edu.rpi.legup.model.elements.PlaceableElement;
+
+public class TipTileFillW extends PlaceableElement {
+ public TipTileFillW() {
+ super(
+ "Therm-PLAC-0036",
+ "Tip Tile Fill West",
+ "The tile corresponding to the filled tip of a west thermometer",
+ "edu/rpi/legup/images/thermometer/Elements/TipFillW.png");
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/DiscontinuousMercuryContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/DiscontinuousMercuryContradictionRule.java
new file mode 100644
index 000000000..b013b3493
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/DiscontinuousMercuryContradictionRule.java
@@ -0,0 +1,62 @@
+package edu.rpi.legup.puzzle.thermometer.rules;
+
+import edu.rpi.legup.model.gameboard.Board;
+import edu.rpi.legup.model.gameboard.PuzzleElement;
+import edu.rpi.legup.model.rules.ContradictionRule;
+import edu.rpi.legup.puzzle.thermometer.ThermometerBoard;
+import edu.rpi.legup.puzzle.thermometer.ThermometerCell;
+import edu.rpi.legup.puzzle.thermometer.ThermometerVial;
+import java.util.ArrayList;
+
+// TODO: Rule is untested
+public class DiscontinuousMercuryContradictionRule extends ContradictionRule {
+
+ private final String NO_CONTRADICTION_MESSAGE =
+ "Does not contain a contradiction at this index";
+ private final String INVALID_USE_MESSAGE = "Contradiction must be a vial";
+
+ public DiscontinuousMercuryContradictionRule() {
+ super(
+ "THERM-CONT-0001",
+ "Discontinuous Mercury",
+ "A vial has a filled cell after an empty or blocked cell",
+ "edu/rpi/legup/images/thermometer/MercuryInBody.png");
+ }
+
+ /**
+ * Checks whether the transition has a contradiction at the specific puzzleElement index using
+ * this rule
+ *
+ * @param board board to check contradiction
+ * @param puzzleElement equivalent puzzleElement
+ * @return null if the transition contains a contradiction at the specified puzzleElement,
+ * otherwise error message
+ */
+ // User can click on any cell in a vial with a discontinuous flow
+ @Override
+ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) {
+ // useful variables
+ ThermometerBoard thermometerBoard = (ThermometerBoard) board;
+
+ ThermometerCell cell = (ThermometerCell) thermometerBoard.getPuzzleElement(puzzleElement);
+
+ ArrayList thermometerVials = thermometerBoard.getVials();
+
+ // finding out which vial contains the specified cell
+ for (int i = 0; i < thermometerVials.size(); i++) {
+ ThermometerVial thermometerVial = thermometerVials.get(i);
+ // if a vial contains the clicked on cell
+ // checking if the vial has a break in the flow
+ if (thermometerVial.containsCell(cell)) {
+ if (thermometerVial.continuousFlow()) {
+ return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE;
+ } else {
+ return null;
+ }
+ }
+ }
+
+ // if none of the vials contain the clicked on cell yell at user
+ return super.getInvalidUseOfRuleMessage() + ": " + this.INVALID_USE_MESSAGE;
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/FinishWithBlockedDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/FinishWithBlockedDirectRule.java
new file mode 100644
index 000000000..d09b98300
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/FinishWithBlockedDirectRule.java
@@ -0,0 +1,44 @@
+package edu.rpi.legup.puzzle.thermometer.rules;
+
+import edu.rpi.legup.model.gameboard.Board;
+import edu.rpi.legup.model.gameboard.PuzzleElement;
+import edu.rpi.legup.model.rules.DirectRule;
+import edu.rpi.legup.model.tree.TreeNode;
+import edu.rpi.legup.model.tree.TreeTransition;
+
+// TODO: Rule is unimplemented
+public class FinishWithBlockedDirectRule extends DirectRule {
+ public FinishWithBlockedDirectRule() {
+ super(
+ "THERM-BASC-0004",
+ "Finish With Blocked",
+ "Remaining tiles must be blocked once requirement is satisfied",
+ "edu/rpi/legup/images/thermometer/FinishWithBlocked.png");
+ }
+
+ /**
+ * Checks whether the child node logically follows from the parent node at the specific
+ * puzzleElement index using this rule
+ *
+ * @param transition transition to check
+ * @param puzzleElement equivalent puzzleElement
+ * @return null if the child node logically follow from the parent node at the specified
+ * puzzleElement, otherwise error message
+ */
+ @Override
+ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) {
+ return null;
+ }
+
+ /**
+ * Creates a transition {@link Board} that has this rule applied to it using the {@link
+ * TreeNode}.
+ *
+ * @param node tree node used to create default transition board
+ * @return default board or null if this rule cannot be applied to this tree node
+ */
+ @Override
+ public Board getDefaultBoard(TreeNode node) {
+ return null;
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/FinishWithMercuryDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/FinishWithMercuryDirectRule.java
new file mode 100644
index 000000000..09fb8874d
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/FinishWithMercuryDirectRule.java
@@ -0,0 +1,44 @@
+package edu.rpi.legup.puzzle.thermometer.rules;
+
+import edu.rpi.legup.model.gameboard.Board;
+import edu.rpi.legup.model.gameboard.PuzzleElement;
+import edu.rpi.legup.model.rules.DirectRule;
+import edu.rpi.legup.model.tree.TreeNode;
+import edu.rpi.legup.model.tree.TreeTransition;
+
+// TODO: Rule is unimplemented
+public class FinishWithMercuryDirectRule extends DirectRule {
+ public FinishWithMercuryDirectRule() {
+ super(
+ "THERM-BASC-0003",
+ "Finish with Mercury",
+ "Remaining tiles must be filled to satisfy requirement",
+ "edu/rpi/legup/images/thermometer/FinishWithMercury.png");
+ }
+
+ /**
+ * Checks whether the child node logically follows from the parent node at the specific
+ * puzzleElement index using this rule
+ *
+ * @param transition transition to check
+ * @param puzzleElement equivalent puzzleElement
+ * @return null if the child node logically follow from the parent node at the specified
+ * puzzleElement, otherwise error message
+ */
+ @Override
+ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) {
+ return null;
+ }
+
+ /**
+ * Creates a transition {@link Board} that has this rule applied to it using the {@link
+ * TreeNode}.
+ *
+ * @param node tree node used to create default transition board
+ * @return default board or null if this rule cannot be applied to this tree node
+ */
+ @Override
+ public Board getDefaultBoard(TreeNode node) {
+ return null;
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/MercuryOrBlockedCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/MercuryOrBlockedCaseRule.java
new file mode 100644
index 000000000..a0644aec0
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/MercuryOrBlockedCaseRule.java
@@ -0,0 +1,114 @@
+package edu.rpi.legup.puzzle.thermometer.rules;
+
+import edu.rpi.legup.model.gameboard.Board;
+import edu.rpi.legup.model.gameboard.CaseBoard;
+import edu.rpi.legup.model.gameboard.PuzzleElement;
+import edu.rpi.legup.model.rules.CaseRule;
+import edu.rpi.legup.model.tree.TreeTransition;
+import edu.rpi.legup.puzzle.thermometer.*;
+import java.util.ArrayList;
+import java.util.List;
+
+// TODO: Rule is untested
+public class MercuryOrBlockedCaseRule extends CaseRule {
+ public MercuryOrBlockedCaseRule() {
+ super(
+ "THERM-CASE-0001",
+ "Mercury or Blocked",
+ "Each unassigned tile must be filled with mercury or blocked.",
+ "edu/rpi/legup/images/thermometer/MercOrBlocked.png");
+ }
+
+ /**
+ * Checks whether the transition logically follows from the parent node using this rule
+ *
+ * @param transition transition to check
+ * @return null if the child node logically follow from the parent node, otherwise error message
+ */
+ @Override
+ public String checkRuleRaw(TreeTransition transition) {
+ List childTransitions = transition.getParents().get(0).getChildren();
+ if (childTransitions.size() != 2) {
+ return super.getInvalidUseOfRuleMessage() + ": This case rule must have 2 children.";
+ }
+
+ TreeTransition case1 = childTransitions.get(0);
+ TreeTransition case2 = childTransitions.get(1);
+ if (case1.getBoard().getModifiedData().size() != 1
+ || case2.getBoard().getModifiedData().size() != 1) {
+ return super.getInvalidUseOfRuleMessage()
+ + ": This case rule must have 1 modified cell for each case.";
+ }
+
+ ThermometerCell mod1 =
+ (ThermometerCell) case1.getBoard().getModifiedData().iterator().next();
+ ThermometerCell mod2 =
+ (ThermometerCell) case2.getBoard().getModifiedData().iterator().next();
+ if (!mod1.getLocation().equals(mod2.getLocation())) {
+ return super.getInvalidUseOfRuleMessage()
+ + ": This case rule must modify the same cell for each case.";
+ }
+
+ if (!((mod1.getFill() == ThermometerFill.BLOCKED
+ && mod2.getFill() == ThermometerFill.FILLED)
+ || (mod2.getFill() == ThermometerFill.BLOCKED
+ && mod1.getFill() == ThermometerFill.FILLED))) {
+ return super.getInvalidUseOfRuleMessage()
+ + ": This case rule must have a filled or blocked cell.";
+ }
+
+ return null;
+ }
+
+ /**
+ * Checks whether the child node logically follows from the parent node at the specific
+ * puzzleElement index using this rule
+ *
+ * @param transition transition to check
+ * @param puzzleElement equivalent puzzleElement
+ * @return null if the child node logically follow from the parent node at the specified
+ * puzzleElement, otherwise error message
+ */
+ @Override
+ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) {
+ return null;
+ }
+
+ @Override
+ public CaseBoard getCaseBoard(Board board) {
+ ThermometerBoard thermometerBoard = (ThermometerBoard) board.copy();
+ CaseBoard caseBoard = new CaseBoard(thermometerBoard, this);
+ thermometerBoard.setModifiable(false);
+ for (PuzzleElement element : thermometerBoard.getPuzzleElements()) {
+ if (((ThermometerCell) element).getFill() == ThermometerFill.UNKNOWN) {
+ caseBoard.addPickableElement(element);
+ }
+ }
+ return caseBoard;
+ }
+
+ /**
+ * Gets the possible cases at a specific location based on this case rule
+ *
+ * @param board the current board state
+ * @param puzzleElement equivalent puzzleElement
+ * @return a list of elements the specified could be
+ */
+ @Override
+ public ArrayList getCases(Board board, PuzzleElement puzzleElement) {
+ ArrayList cases = new ArrayList<>();
+ Board case1 = board.copy();
+ ThermometerCell data1 = (ThermometerCell) case1.getPuzzleElement(puzzleElement);
+ data1.setFill(ThermometerFill.FILLED);
+ case1.addModifiedData(data1);
+ cases.add(case1);
+
+ Board case2 = board.copy();
+ ThermometerCell data2 = (ThermometerCell) case2.getPuzzleElement(puzzleElement);
+ data2.setFill(ThermometerFill.BLOCKED);
+ case2.addModifiedData(data2);
+ cases.add(case2);
+
+ return cases;
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/MinimumFillDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/MinimumFillDirectRule.java
new file mode 100644
index 000000000..ab389d6ff
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/MinimumFillDirectRule.java
@@ -0,0 +1,44 @@
+package edu.rpi.legup.puzzle.thermometer.rules;
+
+import edu.rpi.legup.model.gameboard.Board;
+import edu.rpi.legup.model.gameboard.PuzzleElement;
+import edu.rpi.legup.model.rules.DirectRule;
+import edu.rpi.legup.model.tree.TreeNode;
+import edu.rpi.legup.model.tree.TreeTransition;
+
+// TODO: Rule is unimplemented
+public class MinimumFillDirectRule extends DirectRule {
+ public MinimumFillDirectRule() {
+ super(
+ "THERM-BASC-0005",
+ "Minimum Fill",
+ "Some thermometers must be filled a minimum amount to satisfy requirement",
+ "edu/rpi/legup/images/thermometer/MinimumFill.png");
+ }
+
+ /**
+ * Checks whether the child node logically follows from the parent node at the specific
+ * puzzleElement index using this rule
+ *
+ * @param transition transition to check
+ * @param puzzleElement equivalent puzzleElement
+ * @return null if the child node logically follow from the parent node at the specified
+ * puzzleElement, otherwise error message
+ */
+ @Override
+ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) {
+ return null;
+ }
+
+ /**
+ * Creates a transition {@link Board} that has this rule applied to it using the {@link
+ * TreeNode}.
+ *
+ * @param node tree node used to create default transition board
+ * @return default board or null if this rule cannot be applied to this tree node
+ */
+ @Override
+ public Board getDefaultBoard(TreeNode node) {
+ return null;
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/PriorFilledDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/PriorFilledDirectRule.java
new file mode 100644
index 000000000..61622ddb1
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/PriorFilledDirectRule.java
@@ -0,0 +1,101 @@
+package edu.rpi.legup.puzzle.thermometer.rules;
+
+import edu.rpi.legup.model.gameboard.Board;
+import edu.rpi.legup.model.gameboard.PuzzleElement;
+import edu.rpi.legup.model.rules.DirectRule;
+import edu.rpi.legup.model.tree.TreeNode;
+import edu.rpi.legup.model.tree.TreeTransition;
+import edu.rpi.legup.puzzle.thermometer.ThermometerBoard;
+import edu.rpi.legup.puzzle.thermometer.ThermometerCell;
+import edu.rpi.legup.puzzle.thermometer.ThermometerFill;
+import edu.rpi.legup.puzzle.thermometer.ThermometerVial;
+import java.util.ArrayList;
+
+// TODO: Rule is untested
+public class PriorFilledDirectRule extends DirectRule {
+
+ public PriorFilledDirectRule() {
+ super(
+ "THERM-BASC-0002",
+ "Prior is Filled",
+ "All tiles proceeding a filled tile in a vial must be filled",
+ "edu/rpi/legup/images/thermometer/PriorIsFilled.png");
+ }
+
+ /**
+ * Checks whether the child node logically follows from the parent node at the specific
+ * puzzleElement index using this rule
+ *
+ * @param transition transition to check
+ * @param puzzleElement equivalent puzzleElement
+ * @return null if the child node logically follow from the parent node at the specified
+ * puzzleElement, otherwise error message
+ */
+ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) {
+ ThermometerBoard initialBoard =
+ (ThermometerBoard) transition.getParents().get(0).getBoard();
+ ThermometerBoard finalBoard = (ThermometerBoard) transition.getBoard();
+
+ ThermometerCell cell = (ThermometerCell) finalBoard.getPuzzleElement(puzzleElement);
+ if (cell.getFill() != ThermometerFill.FILLED) {
+ return super.getInvalidUseOfRuleMessage() + ": Cell is not filled at this index";
+ }
+
+ ArrayList allVials = finalBoard.getVials();
+ ThermometerVial host = null;
+ for (ThermometerVial vials : allVials) {
+ if (vials.containsCell((cell))) {
+ host = vials;
+ }
+ }
+ if (host == null) return super.getInvalidUseOfRuleMessage() + ": Something went wrong - 1";
+ int x = (int) cell.getLocation().getX();
+ int y = (int) cell.getLocation().getX();
+
+ // Identifies next cell from tail location, checks if it is filled
+ if (host.getTail() == cell) {
+ return super.getInvalidUseOfRuleMessage() + ": rule can not apply to tail";
+ } else if (host.getTail().getLocation().getX() == x) {
+ if (host.getTail().getLocation().getY() > y) {
+ if (initialBoard.getCell(x, y + 1).getFill() == ThermometerFill.FILLED) {
+ return null;
+ } else {
+ return super.getInvalidUseOfRuleMessage() + "rule does not apply to this cell";
+ }
+ } else if (host.getTail().getLocation().getY() < y) {
+ if (initialBoard.getCell(x, y - 1).getFill() == ThermometerFill.FILLED) {
+ return null;
+ } else {
+ return super.getInvalidUseOfRuleMessage() + "rule does not apply to this cell";
+ }
+ } else return super.getInvalidUseOfRuleMessage() + ": Something went wrong - 2";
+ } else if (host.getTail().getLocation().getY() == y) {
+ if (host.getTail().getLocation().getX() > x) {
+ if (initialBoard.getCell(x + 1, y).getFill() == ThermometerFill.FILLED) {
+ return null;
+ } else {
+ return super.getInvalidUseOfRuleMessage() + "rule does not apply to this cell";
+ }
+ } else if (host.getTail().getLocation().getX() < x) {
+ if (initialBoard.getCell(x - 1, y).getFill() == ThermometerFill.FILLED) {
+ return null;
+ } else {
+ return super.getInvalidUseOfRuleMessage() + "rule does not apply to this cell";
+ }
+ } else return super.getInvalidUseOfRuleMessage() + ": Something went wrong - 2.1";
+ }
+ return super.getInvalidUseOfRuleMessage() + "Something went wrong - 3";
+ }
+
+ /**
+ * Creates a transition {@link Board} that has this rule applied to it using the {@link
+ * TreeNode}.
+ *
+ * @param node tree node used to create default transition board
+ * @return default board or null if this rule cannot be applied to this tree node
+ */
+ @Override
+ public Board getDefaultBoard(TreeNode node) {
+ return null;
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/RestEmptyDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/RestEmptyDirectRule.java
new file mode 100644
index 000000000..486c5c1da
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/RestEmptyDirectRule.java
@@ -0,0 +1,101 @@
+package edu.rpi.legup.puzzle.thermometer.rules;
+
+import edu.rpi.legup.model.gameboard.Board;
+import edu.rpi.legup.model.gameboard.PuzzleElement;
+import edu.rpi.legup.model.rules.DirectRule;
+import edu.rpi.legup.model.tree.TreeNode;
+import edu.rpi.legup.model.tree.TreeTransition;
+import edu.rpi.legup.puzzle.thermometer.ThermometerBoard;
+import edu.rpi.legup.puzzle.thermometer.ThermometerCell;
+import edu.rpi.legup.puzzle.thermometer.ThermometerFill;
+import edu.rpi.legup.puzzle.thermometer.ThermometerVial;
+import java.util.ArrayList;
+
+// TODO: Rule is untested
+public class RestEmptyDirectRule extends DirectRule {
+
+ public RestEmptyDirectRule() {
+ super(
+ "THERM-BASC-0001",
+ "Rest is Empty",
+ "All tiles following a blocked tile in a vial must be blocked",
+ "edu/rpi/legup/images/thermometer/RestIsEmpty.png");
+ }
+
+ /**
+ * Checks whether the child node logically follows from the parent node at the specific
+ * puzzleElement index using this rule
+ *
+ * @param transition transition to check
+ * @param puzzleElement equivalent puzzleElement
+ * @return null if the child node logically follow from the parent node at the specified
+ * puzzleElement, otherwise error message
+ */
+ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) {
+ ThermometerBoard initialBoard =
+ (ThermometerBoard) transition.getParents().get(0).getBoard();
+ ThermometerBoard finalBoard = (ThermometerBoard) transition.getBoard();
+
+ ThermometerCell cell = (ThermometerCell) finalBoard.getPuzzleElement(puzzleElement);
+ if (cell.getFill() != ThermometerFill.BLOCKED) {
+ return super.getInvalidUseOfRuleMessage() + ": Cell is not blocked at this index";
+ }
+
+ ArrayList allVials = finalBoard.getVials();
+ ThermometerVial host = null;
+ for (ThermometerVial vials : allVials) {
+ if (vials.containsCell((cell))) {
+ host = vials;
+ }
+ }
+ if (host == null) return super.getInvalidUseOfRuleMessage() + ": Something went wrong - 1";
+ int x = (int) cell.getLocation().getX();
+ int y = (int) cell.getLocation().getX();
+
+ // Identifies previous cell from head location, checks if it is blocked
+ if (host.getHead() == cell) {
+ return super.getInvalidUseOfRuleMessage() + ": rule can not apply to head";
+ } else if (host.getHead().getLocation().getX() == x) {
+ if (host.getHead().getLocation().getY() > y) {
+ if (initialBoard.getCell(x, y + 1).getFill() == ThermometerFill.BLOCKED) {
+ return null;
+ } else {
+ return super.getInvalidUseOfRuleMessage() + "rule does not apply to this cell";
+ }
+ } else if (host.getHead().getLocation().getY() < y) {
+ if (initialBoard.getCell(x, y - 1).getFill() == ThermometerFill.BLOCKED) {
+ return null;
+ } else {
+ return super.getInvalidUseOfRuleMessage() + "rule does not apply to this cell";
+ }
+ } else return super.getInvalidUseOfRuleMessage() + ": Something went wrong - 2";
+ } else if (host.getHead().getLocation().getY() == y) {
+ if (host.getHead().getLocation().getX() > x) {
+ if (initialBoard.getCell(x + 1, y).getFill() == ThermometerFill.BLOCKED) {
+ return null;
+ } else {
+ return super.getInvalidUseOfRuleMessage() + "rule does not apply to this cell";
+ }
+ } else if (host.getHead().getLocation().getX() < x) {
+ if (initialBoard.getCell(x - 1, y).getFill() == ThermometerFill.BLOCKED) {
+ return null;
+ } else {
+ return super.getInvalidUseOfRuleMessage() + "rule does not apply to this cell";
+ }
+ } else return super.getInvalidUseOfRuleMessage() + ": Something went wrong - 2.1";
+ }
+ return super.getInvalidUseOfRuleMessage() + "Something went wrong - 3";
+ }
+
+ /**
+ * Creates a transition {@link Board} that has this rule applied to it using the {@link
+ * TreeNode}.
+ *
+ * @param node tree node used to create default transition board
+ * @return default board or null if this rule cannot be applied to this tree node
+ */
+ @Override
+ public Board getDefaultBoard(TreeNode node) {
+ return null;
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/SatisfyMercuryCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/SatisfyMercuryCaseRule.java
new file mode 100644
index 000000000..05c861281
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/SatisfyMercuryCaseRule.java
@@ -0,0 +1,62 @@
+package edu.rpi.legup.puzzle.thermometer.rules;
+
+import edu.rpi.legup.model.gameboard.Board;
+import edu.rpi.legup.model.gameboard.CaseBoard;
+import edu.rpi.legup.model.gameboard.PuzzleElement;
+import edu.rpi.legup.model.rules.CaseRule;
+import edu.rpi.legup.model.tree.TreeTransition;
+import edu.rpi.legup.puzzle.thermometer.*;
+import java.util.ArrayList;
+
+// TODO:This rule is unimplemented
+public class SatisfyMercuryCaseRule extends CaseRule {
+ public SatisfyMercuryCaseRule() {
+ super(
+ "THERM-CASE-0002",
+ "Satisfy Mercury",
+ "There are multiple ways column/row requirements can be fufilled",
+ "edu/rpi/legup/images/thermometer/SatisfyMercury.png");
+ }
+
+ /**
+ * Checks whether the transition logically follows from the parent node using this rule
+ *
+ * @param transition transition to check
+ * @return null if the child node logically follow from the parent node, otherwise error message
+ */
+ @Override
+ public String checkRuleRaw(TreeTransition transition) {
+ return null;
+ }
+
+ /**
+ * Checks whether the child node logically follows from the parent node at the specific
+ * puzzleElement index using this rule
+ *
+ * @param transition transition to check
+ * @param puzzleElement equivalent puzzleElement
+ * @return null if the child node logically follow from the parent node at the specified
+ * puzzleElement, otherwise error message
+ */
+ @Override
+ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) {
+ return null;
+ }
+
+ /**
+ * Gets the possible cases at a specific location based on this case rule
+ *
+ * @param board the current board state
+ * @param puzzleElement equivalent puzzleElement
+ * @return a list of elements the specified could be
+ */
+ @Override
+ public ArrayList getCases(Board board, PuzzleElement puzzleElement) {
+ return null;
+ }
+
+ @Override
+ public CaseBoard getCaseBoard(Board board) {
+ return null;
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/ThermometerTooLargeDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/ThermometerTooLargeDirectRule.java
new file mode 100644
index 000000000..d679781b7
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/ThermometerTooLargeDirectRule.java
@@ -0,0 +1,44 @@
+package edu.rpi.legup.puzzle.thermometer.rules;
+
+import edu.rpi.legup.model.gameboard.Board;
+import edu.rpi.legup.model.gameboard.PuzzleElement;
+import edu.rpi.legup.model.rules.DirectRule;
+import edu.rpi.legup.model.tree.TreeNode;
+import edu.rpi.legup.model.tree.TreeTransition;
+
+// TODO: Rule is unimplemented
+public class ThermometerTooLargeDirectRule extends DirectRule {
+ public ThermometerTooLargeDirectRule() {
+ super(
+ "THERM-BASC-0006",
+ "Thermometer Too Large",
+ "If thermometer is larger than required mercury, some of it must be blocked",
+ "edu/rpi/legup/images/thermometer/ThermometerTooLarge.png");
+ }
+
+ /**
+ * Checks whether the child node logically follows from the parent node at the specific
+ * puzzleElement index using this rule
+ *
+ * @param transition transition to check
+ * @param puzzleElement equivalent puzzleElement
+ * @return null if the child node logically follow from the parent node at the specified
+ * puzzleElement, otherwise error message
+ */
+ @Override
+ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) {
+ return null;
+ }
+
+ /**
+ * Creates a transition {@link Board} that has this rule applied to it using the {@link
+ * TreeNode}.
+ *
+ * @param node tree node used to create default transition board
+ * @return default board or null if this rule cannot be applied to this tree node
+ */
+ @Override
+ public Board getDefaultBoard(TreeNode node) {
+ return null;
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/TooFewMercuryContradiction.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/TooFewMercuryContradiction.java
new file mode 100644
index 000000000..8750eb64d
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/TooFewMercuryContradiction.java
@@ -0,0 +1,57 @@
+package edu.rpi.legup.puzzle.thermometer.rules;
+
+import edu.rpi.legup.model.gameboard.Board;
+import edu.rpi.legup.model.gameboard.PuzzleElement;
+import edu.rpi.legup.model.rules.ContradictionRule;
+import edu.rpi.legup.puzzle.thermometer.ThermometerBoard;
+import edu.rpi.legup.puzzle.thermometer.ThermometerCell;
+import edu.rpi.legup.puzzle.thermometer.ThermometerFill;
+
+// TODO: Rule is untested
+public class TooFewMercuryContradiction extends ContradictionRule {
+
+ private final String Invalid_Use_Message = "Mercury can still reach limit";
+
+ public TooFewMercuryContradiction() {
+ super(
+ "THERM-CONT-0002",
+ "Too Few Mercury",
+ "Not enough mercury in column/row to fufill requirement",
+ "edu/rpi/legup/images/thermometer/NotEnoughMercury.png");
+ }
+
+ /**
+ * Checks whether the transition has a contradiction at the specific puzzleElement index using
+ * this rule
+ *
+ * @param board board to check contradiction
+ * @param puzzleElement equivalent puzzleElement
+ * @return null if the transition contains a contradiction at the specified puzzleElement,
+ * otherwise error message
+ */
+ @Override
+ // Checks if row or column of input element has too many blocked tiles
+ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) {
+ ThermometerBoard grid = (ThermometerBoard) board;
+ ThermometerCell cell = (ThermometerCell) grid.getPuzzleElement(puzzleElement);
+ int blocked = 0;
+ for (int i = 0; i < grid.getHeight(); i++) {
+ if (grid.getCell((int) cell.getLocation().getX(), i).getFill()
+ == ThermometerFill.BLOCKED) {
+ blocked++;
+ }
+ }
+ if (grid.getRowNumber((int) cell.getLocation().getX()) > blocked) return null;
+
+ blocked = 0;
+ for (int i = 0; i < grid.getWidth(); i++) {
+ if (grid.getCell(i, (int) cell.getLocation().getY()).getFill()
+ == ThermometerFill.BLOCKED) {
+ blocked++;
+ }
+ }
+ if (grid.getColNumber((int) cell.getLocation().getY()) > blocked) return null;
+
+ return Invalid_Use_Message;
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/TooManyMercuryContradiction.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/TooManyMercuryContradiction.java
new file mode 100644
index 000000000..06b8a017c
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/TooManyMercuryContradiction.java
@@ -0,0 +1,56 @@
+package edu.rpi.legup.puzzle.thermometer.rules;
+
+import edu.rpi.legup.model.gameboard.Board;
+import edu.rpi.legup.model.gameboard.PuzzleElement;
+import edu.rpi.legup.model.rules.ContradictionRule;
+import edu.rpi.legup.puzzle.thermometer.ThermometerBoard;
+import edu.rpi.legup.puzzle.thermometer.ThermometerCell;
+import edu.rpi.legup.puzzle.thermometer.ThermometerFill;
+
+// TODO: Rule is untested
+public class TooManyMercuryContradiction extends ContradictionRule {
+
+ private final String Invalid_Use_Message = "Mercury does not exceed limit";
+
+ public TooManyMercuryContradiction() {
+ super(
+ "THERM-CONT-0003",
+ "Too Many Mercury",
+ "More mercury in column/row than target",
+ "edu/rpi/legup/images/thermometer/TooManyMercury.png");
+ }
+
+ /**
+ * Checks whether the transition has a contradiction at the specific puzzleElement index using
+ * this rule
+ *
+ * @param board board to check contradiction
+ * @param puzzleElement equivalent puzzleElement
+ * @return null if the transition contains a contradiction at the specified puzzleElement,
+ * otherwise error message
+ */
+ @Override
+ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) {
+ ThermometerBoard grid = (ThermometerBoard) board;
+ ThermometerCell cell = (ThermometerCell) grid.getPuzzleElement(puzzleElement);
+ int filled = 0;
+ for (int i = 0; i < grid.getHeight(); i++) {
+ if (grid.getCell((int) cell.getLocation().getX(), i).getFill()
+ == ThermometerFill.FILLED) {
+ filled++;
+ }
+ }
+ if (grid.getRowNumber((int) cell.getLocation().getX()) > filled) return null;
+
+ filled = 0;
+ for (int i = 0; i < grid.getWidth(); i++) {
+ if (grid.getCell(i, (int) cell.getLocation().getY()).getFill()
+ == ThermometerFill.FILLED) {
+ filled++;
+ }
+ }
+ if (grid.getColNumber((int) cell.getLocation().getY()) > filled) return null;
+
+ return Invalid_Use_Message;
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/thermometer_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/thermometer_reference_sheet.txt
new file mode 100644
index 000000000..546fb89a6
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/thermometer_reference_sheet.txt
@@ -0,0 +1,16 @@
+THERM-BASC-0001 : RestEmptyDirectRule
+THERM-BASC-0002 : PriorFilledDirectRule
+THERM-BASC-0003 : FinishWithMercuryDirectRule
+THERM-BASC-0004 : FinishWithBlockedDirectRule
+THERM-BASC-0005 : MinimumFillDirectRule
+THERM-BASC-0006 : ThermometerTooLargeDirectRule
+
+THERM-CONT-0001 : DiscontinuousMercuryContradictionRule
+THERM-CONT-0002 : TooFewMercuryContradiction
+THERM-CONT-0003 : TooManyMercuryContradiction
+
+THERM-CASE-0001 : MercuryOrBlockedCaseRule
+THERM-CASE-0002 : SatisfyMercuryCaseRule
+
+Images can be found/edited here:
+https://docs.google.com/presentation/d/1YHNog2fGvLJEx4kbJZiwwAlP-m2-E1O7hGh0HJ7S0gE/edit?usp=sharing
\ No newline at end of file
diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Element Template.png b/src/main/resources/edu/rpi/legup/images/thermometer/Element Template.png
new file mode 100644
index 000000000..52e3e36b7
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Element Template.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadBlockE.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadBlockE.png
new file mode 100644
index 000000000..238a301af
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadBlockE.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadBlockN.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadBlockN.png
new file mode 100644
index 000000000..8f343a3ba
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadBlockN.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadBlockS.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadBlockS.png
new file mode 100644
index 000000000..f95536076
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadBlockS.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadBlockW.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadBlockW.png
new file mode 100644
index 000000000..b1bbd31be
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadBlockW.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadEmpE.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadEmpE.png
new file mode 100644
index 000000000..852043171
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadEmpE.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadEmpN.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadEmpN.png
new file mode 100644
index 000000000..78179a633
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadEmpN.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadEmpS.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadEmpS.png
new file mode 100644
index 000000000..463b4308c
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadEmpS.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadEmpW.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadEmpW.png
new file mode 100644
index 000000000..19240e5fc
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadEmpW.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadFillE.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadFillE.png
new file mode 100644
index 000000000..d577c25f5
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadFillE.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadFillN.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadFillN.png
new file mode 100644
index 000000000..9905da3aa
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadFillN.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadFillS.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadFillS.png
new file mode 100644
index 000000000..2e6c6d75d
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadFillS.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadFillW.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadFillW.png
new file mode 100644
index 000000000..94ad0b2b4
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadFillW.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftBlockE.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftBlockE.png
new file mode 100644
index 000000000..d351674c5
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftBlockE.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftBlockN.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftBlockN.png
new file mode 100644
index 000000000..505aa6ec9
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftBlockN.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftBlockS.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftBlockS.png
new file mode 100644
index 000000000..91356f95e
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftBlockS.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftBlockW.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftBlockW.png
new file mode 100644
index 000000000..6013fca19
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftBlockW.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftEmpE.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftEmpE.png
new file mode 100644
index 000000000..b038ea65f
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftEmpE.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftEmpN.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftEmpN.png
new file mode 100644
index 000000000..c59c1a930
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftEmpN.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftEmpS.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftEmpS.png
new file mode 100644
index 000000000..f70a25cf1
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftEmpS.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftEmpW.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftEmpW.png
new file mode 100644
index 000000000..48cde1b37
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftEmpW.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftFillE.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftFillE.png
new file mode 100644
index 000000000..06a507b74
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftFillE.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftFillN.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftFillN.png
new file mode 100644
index 000000000..26c177a91
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftFillN.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftFillS.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftFillS.png
new file mode 100644
index 000000000..046b96e26
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftFillS.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftFillW.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftFillW.png
new file mode 100644
index 000000000..3688bbe0a
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftFillW.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipBlockE.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipBlockE.png
new file mode 100644
index 000000000..d78a9723a
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipBlockE.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipBlockN.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipBlockN.png
new file mode 100644
index 000000000..eca516d89
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipBlockN.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipBlockS.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipBlockS.png
new file mode 100644
index 000000000..a207de1c4
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipBlockS.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipBlockW.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipBlockW.png
new file mode 100644
index 000000000..f48ff2b28
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipBlockW.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipEmpE.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipEmpE.png
new file mode 100644
index 000000000..660506aa7
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipEmpE.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipEmpN.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipEmpN.png
new file mode 100644
index 000000000..ae3ca519d
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipEmpN.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipEmpS.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipEmpS.png
new file mode 100644
index 000000000..62f60dfb4
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipEmpS.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipEmpW.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipEmpW.png
new file mode 100644
index 000000000..d67801d76
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipEmpW.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipFillE.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipFillE.png
new file mode 100644
index 000000000..1f24029e5
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipFillE.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipFillN.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipFillN.png
new file mode 100644
index 000000000..e7abdb0bb
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipFillN.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipFillS.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipFillS.png
new file mode 100644
index 000000000..bfb506b99
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipFillS.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipFillW.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipFillW.png
new file mode 100644
index 000000000..e931a7555
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipFillW.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/FinishWithBlocked.png b/src/main/resources/edu/rpi/legup/images/thermometer/FinishWithBlocked.png
new file mode 100644
index 000000000..0a36aa3ac
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/FinishWithBlocked.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/FinishWithMercury.png b/src/main/resources/edu/rpi/legup/images/thermometer/FinishWithMercury.png
new file mode 100644
index 000000000..6693e2d7b
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/FinishWithMercury.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/MercOrBlocked.png b/src/main/resources/edu/rpi/legup/images/thermometer/MercOrBlocked.png
new file mode 100644
index 000000000..66c994de0
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/MercOrBlocked.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/MercuryInBody.png b/src/main/resources/edu/rpi/legup/images/thermometer/MercuryInBody.png
new file mode 100644
index 000000000..06cb87e42
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/MercuryInBody.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/MinimumFill.png b/src/main/resources/edu/rpi/legup/images/thermometer/MinimumFill.png
new file mode 100644
index 000000000..28719cf53
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/MinimumFill.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/NotEnoughMercury.png b/src/main/resources/edu/rpi/legup/images/thermometer/NotEnoughMercury.png
new file mode 100644
index 000000000..d2277e8ef
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/NotEnoughMercury.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/PriorIsFilled.png b/src/main/resources/edu/rpi/legup/images/thermometer/PriorIsFilled.png
new file mode 100644
index 000000000..9bda3a60b
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/PriorIsFilled.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/RestIsEmpty.png b/src/main/resources/edu/rpi/legup/images/thermometer/RestIsEmpty.png
new file mode 100644
index 000000000..91374e062
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/RestIsEmpty.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/SatisfyMercury.png b/src/main/resources/edu/rpi/legup/images/thermometer/SatisfyMercury.png
new file mode 100644
index 000000000..f450a205e
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/SatisfyMercury.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/ThermometerTooLarge.png b/src/main/resources/edu/rpi/legup/images/thermometer/ThermometerTooLarge.png
new file mode 100644
index 000000000..eb61b4f1b
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/ThermometerTooLarge.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/TooManyMercury.png b/src/main/resources/edu/rpi/legup/images/thermometer/TooManyMercury.png
new file mode 100644
index 000000000..99a215b12
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/TooManyMercury.png differ
diff --git a/src/main/resources/edu/rpi/legup/legup/config b/src/main/resources/edu/rpi/legup/legup/config
index a6e2fad7d..1ee9ed79c 100644
--- a/src/main/resources/edu/rpi/legup/legup/config
+++ b/src/main/resources/edu/rpi/legup/legup/config
@@ -43,13 +43,17 @@
qualifiedClassName="edu.rpi.legup.puzzle.treetent.TreeTent"
fileType=".xml"
fileCreationDisabled="false"/>
-
-
+
+
+