diff --git a/bin/main/edu/rpi/legup/legup/config b/bin/main/edu/rpi/legup/legup/config
deleted file mode 100644
index 4aef6de60..000000000
--- a/bin/main/edu/rpi/legup/legup/config
+++ /dev/null
@@ -1,47 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/puzzles files/binary/6x6 easy/089764562 b/puzzles files/binary/6x6 easy/089764562
new file mode 100644
index 000000000..7b22ffc10
--- /dev/null
+++ b/puzzles files/binary/6x6 easy/089764562
@@ -0,0 +1,22 @@
+
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
\ No newline at end of file
diff --git a/puzzles files/binary/6x6 easy/128903434 b/puzzles files/binary/6x6 easy/128903434
new file mode 100644
index 000000000..ea8ef93b0
--- /dev/null
+++ b/puzzles files/binary/6x6 easy/128903434
@@ -0,0 +1,21 @@
+
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
+
\ No newline at end of file
diff --git a/puzzles files/binary/6x6 easy/876868768 b/puzzles files/binary/6x6 easy/876868768
new file mode 100644
index 000000000..0f0ff745e
--- /dev/null
+++ b/puzzles files/binary/6x6 easy/876868768
@@ -0,0 +1,25 @@
+
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
+
\ No newline at end of file
diff --git a/puzzles files/binary/6x6 easy/927364891 b/puzzles files/binary/6x6 easy/927364891
new file mode 100644
index 000000000..da76d067b
--- /dev/null
+++ b/puzzles files/binary/6x6 easy/927364891
@@ -0,0 +1,28 @@
+
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java b/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java
new file mode 100644
index 000000000..773513cda
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java
@@ -0,0 +1,71 @@
+package edu.rpi.legup.puzzle.binary;
+
+import edu.rpi.legup.model.Puzzle;
+import edu.rpi.legup.model.gameboard.Board;
+import edu.rpi.legup.model.gameboard.PuzzleElement;
+import edu.rpi.legup.model.rules.ContradictionRule;
+
+public class Binary extends Puzzle {
+ public Binary() {
+ super();
+
+ this.name = "Binary";
+
+ this.importer = new BinaryImporter(this);
+ this.exporter = new BinaryExporter(this);
+
+ this.factory = new BinaryCellFactory();
+ }
+
+ /** Initializes the game board. Called by the invoker of the class */
+ @Override
+ public void initializeView() {
+ boardView = new BinaryView((BinaryBoard) 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 given dimensions are valid for Binary
+ // *
+ // * @param rows the number of rows
+ // * @param columns the number of columns
+ // * @return true if the given dimensions are valid for Binary, false otherwise
+ // */
+ // @Override
+ // public boolean isValidDimensions(int rows, int columns){
+ // return rows >= 2 && rows % 2 == 0 && columns >= 2 && columns % 2 == 0;
+ // }
+
+ @Override
+ public boolean isBoardComplete(Board board) {
+ BinaryBoard binaryBoard = (BinaryBoard) board;
+
+ for (ContradictionRule rule : contradictionRules) {
+ if (rule.checkContradiction(binaryBoard) == null) {
+ return false;
+ }
+ }
+ for (PuzzleElement data : binaryBoard.getPuzzleElements()) {
+ BinaryCell cell = (BinaryCell) data;
+ if (cell.getType() == BinaryType.UNKNOWN) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public void onBoardChange(Board board) {}
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java
new file mode 100644
index 000000000..35c37b1a1
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java
@@ -0,0 +1,84 @@
+package edu.rpi.legup.puzzle.binary;
+
+import edu.rpi.legup.model.gameboard.GridBoard;
+import edu.rpi.legup.model.gameboard.PuzzleElement;
+import java.awt.*;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+
+public class BinaryBoard extends GridBoard {
+ private int size;
+
+ public BinaryBoard(int width, int height) {
+ super(width, height);
+ this.size = width;
+ }
+
+ public BinaryBoard(int size) {
+ super(size, size);
+ this.size = size;
+ }
+
+ @Override
+ public BinaryCell getCell(int x, int y) {
+ if (y * dimension.width + x >= puzzleElements.size()
+ || x >= dimension.width
+ || y >= dimension.height
+ || x < 0
+ || y < 0) {
+ return null;
+ }
+ return (BinaryCell) super.getCell(x, y);
+ }
+
+ public Set getRowCells(int rowNum) {
+ Set row = new HashSet<>();
+ for (int i = 0; i < size; i++) {
+ BinaryCell cell = getCell(i, rowNum);
+ row.add(cell);
+ }
+ return row;
+ }
+
+ public ArrayList getRowTypes(int rowNum) {
+ ArrayList row = new ArrayList();
+ for (int i = 0; i < size; i++) {
+ BinaryCell cell = getCell(i, rowNum);
+ row.add(cell.getType());
+ }
+ return row;
+ }
+
+ public ArrayList getColTypes(int colNum) {
+ ArrayList col = new ArrayList();
+ for (int i = 0; i < size; i++) {
+ BinaryCell cell = getCell(colNum, i);
+ col.add(cell.getType());
+ }
+ return col;
+ }
+
+ public Set getCol(int colNum) {
+ Set col = new HashSet<>();
+ for (int i = 0; i < size; i++) {
+ col.add(getCell(colNum, i));
+ }
+ return col;
+ }
+
+ @Override
+ public BinaryBoard copy() {
+ System.out.println("BinaryBoard copy()");
+ BinaryBoard copy = new BinaryBoard(dimension.width, dimension.height);
+ for (int x = 0; x < this.dimension.width; x++) {
+ for (int y = 0; y < this.dimension.height; y++) {
+ copy.setCell(x, y, getCell(x, y).copy());
+ }
+ }
+ for (PuzzleElement e : modifiedData) {
+ copy.getPuzzleElement(e).setModifiable(false);
+ }
+ return copy;
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java
new file mode 100644
index 000000000..9007215ad
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java
@@ -0,0 +1,35 @@
+package edu.rpi.legup.puzzle.binary;
+
+import edu.rpi.legup.model.gameboard.GridCell;
+import java.awt.Point;
+
+public class BinaryCell extends GridCell {
+ public BinaryCell(int valueInt, Point location) {
+ super(valueInt, location);
+ }
+
+ public BinaryType getType() {
+ switch (data) {
+ case 0:
+ return BinaryType.ZERO;
+ case 1:
+ return BinaryType.ONE;
+ case 2:
+ return BinaryType.UNKNOWN;
+ default:
+ if (data > 1) {
+ return BinaryType.UNKNOWN;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public BinaryCell copy() {
+ BinaryCell copy = new BinaryCell(data, (Point) location.clone());
+ copy.setIndex(index);
+ copy.setModifiable(isModifiable);
+ copy.setGiven(isGiven);
+ return copy;
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCellFactory.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCellFactory.java
new file mode 100644
index 000000000..890c26656
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCellFactory.java
@@ -0,0 +1,59 @@
+package edu.rpi.legup.puzzle.binary;
+
+import edu.rpi.legup.model.gameboard.Board;
+import edu.rpi.legup.model.gameboard.ElementFactory;
+import edu.rpi.legup.model.gameboard.PuzzleElement;
+import edu.rpi.legup.save.InvalidFileFormatException;
+import java.awt.*;
+import org.w3c.dom.Document;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+
+public class BinaryCellFactory extends ElementFactory {
+
+ public BinaryCell importCell(Node node, Board board) throws InvalidFileFormatException {
+ try {
+ if (!node.getNodeName().equalsIgnoreCase("cell")) {
+ throw new InvalidFileFormatException(
+ "binary Factory: unknown puzzleElement puzzleElement");
+ }
+
+ BinaryBoard binaryBoard = (BinaryBoard) board;
+ int width = binaryBoard.getWidth();
+ int height = binaryBoard.getHeight();
+
+ NamedNodeMap attributeList = node.getAttributes();
+ int value = Integer.valueOf(attributeList.getNamedItem("value").getNodeValue());
+ int x = Integer.valueOf(attributeList.getNamedItem("x").getNodeValue());
+ int y = Integer.valueOf(attributeList.getNamedItem("y").getNodeValue());
+
+ if (x >= width || y >= height) {
+ throw new InvalidFileFormatException("binary Factory: cell location out of bounds");
+ }
+ if (value < -2) {
+ throw new InvalidFileFormatException("binary Factory: cell unknown value");
+ }
+
+ BinaryCell cell = new BinaryCell(value, new Point(x, y));
+ cell.setIndex(y * height + x);
+ return cell;
+ } catch (NumberFormatException e) {
+ throw new InvalidFileFormatException(
+ "binary Factory: unknown value where integer expected");
+ } catch (NullPointerException e) {
+ throw new InvalidFileFormatException("binary Factory: could not find attribute(s)");
+ }
+ }
+
+ public org.w3c.dom.Element exportCell(Document document, PuzzleElement puzzleElement) {
+ org.w3c.dom.Element cellElement = document.createElement("cell");
+
+ BinaryCell cell = (BinaryCell) puzzleElement;
+ Point loc = cell.getLocation();
+ cellElement.setAttribute("value", String.valueOf(cell.getData()));
+ cellElement.setAttribute("x", String.valueOf(loc.x));
+ cellElement.setAttribute("y", String.valueOf(loc.y));
+
+ return cellElement;
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryController.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryController.java
new file mode 100644
index 000000000..0bad559d9
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryController.java
@@ -0,0 +1,45 @@
+package edu.rpi.legup.puzzle.binary;
+
+import edu.rpi.legup.controller.ElementController;
+import edu.rpi.legup.model.gameboard.PuzzleElement;
+import java.awt.event.MouseEvent;
+
+public class BinaryController extends ElementController {
+
+ @Override
+ public void changeCell(MouseEvent e, PuzzleElement data) {
+ BinaryCell cell = (BinaryCell) 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.getData() == 0) {
+ data.setData(1);
+ } else {
+ if (cell.getData() == 1) {
+ data.setData(2);
+ } else {
+ data.setData(0);
+ }
+ }
+ }
+ } else {
+ if (e.getButton() == MouseEvent.BUTTON3) {
+ if (cell.getData() == 0) {
+ data.setData(1);
+ } else {
+ if (cell.getData() == 1) {
+ data.setData(2);
+ } else {
+ data.setData(0);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryElementView.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryElementView.java
new file mode 100644
index 000000000..9ac99c958
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryElementView.java
@@ -0,0 +1,120 @@
+package edu.rpi.legup.puzzle.binary;
+
+import edu.rpi.legup.ui.boardview.GridElementView;
+import java.awt.*;
+
+public class BinaryElementView extends GridElementView {
+
+ private static final Font FONT = new Font("TimesRoman", Font.BOLD, 17);
+ private static final Color FONT_COLOR = Color.BLACK;
+
+ public BinaryElementView(BinaryCell cell) {
+ super(cell);
+ }
+
+ /**
+ * Gets the PuzzleElement associated with this view
+ *
+ * @return PuzzleElement associated with this view
+ */
+ @Override
+ public BinaryCell getPuzzleElement() {
+ return (BinaryCell) super.getPuzzleElement();
+ }
+
+ @Override
+ public void drawGiven(Graphics2D graphics2D) {
+ BinaryCell cell = (BinaryCell) puzzleElement;
+ BinaryType type = cell.getType();
+ if (type == BinaryType.ZERO) {
+ graphics2D.setStroke(new BasicStroke(1));
+ graphics2D.setColor(Color.LIGHT_GRAY);
+ graphics2D.fillRect(location.x, location.y, size.width, size.height);
+ graphics2D.setColor(Color.BLACK);
+ graphics2D.drawRect(location.x, location.y, size.width, size.height);
+ graphics2D.setColor(FONT_COLOR);
+ graphics2D.setFont(FONT);
+ FontMetrics metrics = graphics2D.getFontMetrics(FONT);
+ String value = String.valueOf(puzzleElement.getData());
+ int xText = location.x + (size.width - metrics.stringWidth(value)) / 2;
+ int yText =
+ location.y + ((size.height - metrics.getHeight()) / 2) + metrics.getAscent();
+ graphics2D.drawString(String.valueOf(puzzleElement.getData()), xText, yText);
+ } else {
+ if (type == BinaryType.ONE) {
+ graphics2D.setStroke(new BasicStroke(1));
+ graphics2D.setColor(Color.LIGHT_GRAY);
+ graphics2D.fillRect(location.x, location.y, size.width, size.height);
+ graphics2D.setColor(Color.BLACK);
+ graphics2D.drawRect(location.x, location.y, size.width, size.height);
+ graphics2D.setColor(FONT_COLOR);
+ graphics2D.setFont(FONT);
+ FontMetrics metrics = graphics2D.getFontMetrics(FONT);
+ String value = String.valueOf(puzzleElement.getData());
+ int xText = location.x + (size.width - metrics.stringWidth(value)) / 2;
+ int yText =
+ location.y
+ + ((size.height - metrics.getHeight()) / 2)
+ + metrics.getAscent();
+ graphics2D.drawString(String.valueOf(puzzleElement.getData()), xText, yText);
+
+ } else {
+ if (type == BinaryType.UNKNOWN) {
+ graphics2D.setStroke(new BasicStroke(0));
+ graphics2D.setColor(Color.WHITE);
+ graphics2D.fillRect(location.x, location.y, size.width, size.height);
+ graphics2D.setColor(Color.BLACK);
+ graphics2D.drawRect(location.x, location.y, size.width, size.height);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void drawElement(Graphics2D graphics2D) {
+ BinaryCell cell = (BinaryCell) puzzleElement;
+ BinaryType type = cell.getType();
+ if (type == BinaryType.ZERO) {
+ graphics2D.setStroke(new BasicStroke(1));
+ graphics2D.setColor(Color.WHITE);
+ graphics2D.fillRect(location.x, location.y, size.width, size.height);
+ graphics2D.setColor(Color.BLACK);
+ graphics2D.drawRect(location.x, location.y, size.width, size.height);
+ graphics2D.setColor(FONT_COLOR);
+ graphics2D.setFont(FONT);
+ FontMetrics metrics = graphics2D.getFontMetrics(FONT);
+ String value = String.valueOf(puzzleElement.getData());
+ int xText = location.x + (size.width - metrics.stringWidth(value)) / 2;
+ int yText =
+ location.y + ((size.height - metrics.getHeight()) / 2) + metrics.getAscent();
+ graphics2D.drawString(String.valueOf(puzzleElement.getData()), xText, yText);
+ } else {
+ if (type == BinaryType.ONE) {
+ graphics2D.setStroke(new BasicStroke(1));
+ graphics2D.setColor(Color.WHITE);
+ graphics2D.fillRect(location.x, location.y, size.width, size.height);
+ graphics2D.setColor(Color.BLACK);
+ graphics2D.drawRect(location.x, location.y, size.width, size.height);
+ graphics2D.setColor(FONT_COLOR);
+ graphics2D.setFont(FONT);
+ FontMetrics metrics = graphics2D.getFontMetrics(FONT);
+ String value = String.valueOf(puzzleElement.getData());
+ int xText = location.x + (size.width - metrics.stringWidth(value)) / 2;
+ int yText =
+ location.y
+ + ((size.height - metrics.getHeight()) / 2)
+ + metrics.getAscent();
+ graphics2D.drawString(String.valueOf(puzzleElement.getData()), xText, yText);
+
+ } else {
+ if (type == BinaryType.UNKNOWN) {
+ graphics2D.setStroke(new BasicStroke(0));
+ graphics2D.setColor(Color.WHITE);
+ graphics2D.fillRect(location.x, location.y, size.width, size.height);
+ graphics2D.setColor(Color.BLACK);
+ graphics2D.drawRect(location.x, location.y, size.width, size.height);
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryExporter.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryExporter.java
new file mode 100644
index 000000000..cd58314b6
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryExporter.java
@@ -0,0 +1,39 @@
+package edu.rpi.legup.puzzle.binary;
+
+import edu.rpi.legup.model.PuzzleExporter;
+import edu.rpi.legup.model.gameboard.PuzzleElement;
+import org.w3c.dom.Document;
+
+public class BinaryExporter extends PuzzleExporter {
+
+ public BinaryExporter(Binary binary) {
+ super(binary);
+ }
+
+ @Override
+ protected org.w3c.dom.Element createBoardElement(Document newDocument) {
+ BinaryBoard board;
+ if (puzzle.getTree() != null) {
+ board = (BinaryBoard) puzzle.getTree().getRootNode().getBoard();
+ } else {
+ board = (BinaryBoard) puzzle.getBoardView().getBoard();
+ }
+
+ org.w3c.dom.Element boardElement = newDocument.createElement("board");
+ boardElement.setAttribute("width", String.valueOf(board.getWidth()));
+ boardElement.setAttribute("height", String.valueOf(board.getHeight()));
+
+ org.w3c.dom.Element cellsElement = newDocument.createElement("cells");
+ for (PuzzleElement puzzleElement : board.getPuzzleElements()) {
+ BinaryCell cell = (BinaryCell) puzzleElement;
+ if (cell.getData() != -2) {
+ org.w3c.dom.Element cellElement =
+ puzzle.getFactory().exportCell(newDocument, puzzleElement);
+ cellsElement.appendChild(cellElement);
+ }
+ }
+
+ boardElement.appendChild(cellsElement);
+ return boardElement;
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryImporter.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryImporter.java
new file mode 100644
index 000000000..2fc5b09ef
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryImporter.java
@@ -0,0 +1,117 @@
+package edu.rpi.legup.puzzle.binary;
+
+import edu.rpi.legup.model.PuzzleImporter;
+import edu.rpi.legup.save.InvalidFileFormatException;
+import java.awt.*;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+public class BinaryImporter extends PuzzleImporter {
+ public BinaryImporter(Binary binary) {
+ super(binary);
+ }
+
+ @Override
+ public boolean acceptsRowsAndColumnsInput() {
+ return true;
+ }
+
+ @Override
+ public boolean acceptsTextInput() {
+ return false;
+ }
+
+ @Override
+ public void initializeBoard(int rows, int columns) {
+ BinaryBoard binaryBoard = new BinaryBoard(columns, rows);
+
+ for (int y = 0; y < rows; y++) {
+ for (int x = 0; x < columns; x++) {
+ BinaryCell cell = new BinaryCell(BinaryType.UNKNOWN.toValue(), new Point(x, y));
+ cell.setIndex(y * columns + x);
+ cell.setModifiable(true);
+ binaryBoard.setCell(x, y, cell);
+ }
+ }
+ puzzle.setCurrentBoard(binaryBoard);
+ }
+
+ /**
+ * Creates the board for building
+ *
+ * @param node xml document node
+ * @throws InvalidFileFormatException if file is invalid
+ */
+ @Override
+ public void initializeBoard(Node node) throws InvalidFileFormatException {
+ try {
+ if (!node.getNodeName().equalsIgnoreCase("board")) {
+ throw new InvalidFileFormatException(
+ "binary Importer: cannot find board puzzleElement");
+ }
+ Element boardElement = (Element) node;
+ if (boardElement.getElementsByTagName("cells").getLength() == 0) {
+ throw new InvalidFileFormatException(
+ "binary Importer: no puzzleElement found for board");
+ }
+
+ Element dataElement = (Element) boardElement.getElementsByTagName("cells").item(0);
+ NodeList elementDataList = dataElement.getElementsByTagName("cell");
+
+ BinaryBoard binaryBoard = null;
+ if (!boardElement.getAttribute("size").isEmpty()) {
+ int size = Integer.valueOf(boardElement.getAttribute("size"));
+ binaryBoard = new BinaryBoard(size);
+ } else {
+ if (!boardElement.getAttribute("width").isEmpty()
+ && !boardElement.getAttribute("height").isEmpty()) {
+ int width = Integer.valueOf(boardElement.getAttribute("width"));
+ int height = Integer.valueOf(boardElement.getAttribute("height"));
+ binaryBoard = new BinaryBoard(width, height);
+ }
+ }
+
+ int width = binaryBoard.getWidth();
+ int height = binaryBoard.getHeight();
+
+ if (binaryBoard == null || width % 2 != 0 || height % 2 != 0) {
+ throw new InvalidFileFormatException("binary Importer: invalid board dimensions");
+ }
+
+ for (int i = 0; i < elementDataList.getLength(); i++) {
+ BinaryCell cell =
+ (BinaryCell)
+ puzzle.getFactory()
+ .importCell(elementDataList.item(i), binaryBoard);
+ Point loc = cell.getLocation();
+ if (cell.getData() != BinaryType.UNKNOWN.toValue()) {
+ cell.setModifiable(false);
+ cell.setGiven(true);
+ }
+ binaryBoard.setCell(loc.x, loc.y, cell);
+ }
+
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ if (binaryBoard.getCell(x, y) == null) {
+ BinaryCell cell =
+ new BinaryCell(BinaryType.UNKNOWN.toValue(), new Point(x, y));
+ cell.setIndex(y * height + x);
+ cell.setModifiable(true);
+ binaryBoard.setCell(x, y, cell);
+ }
+ }
+ }
+ puzzle.setCurrentBoard(binaryBoard);
+ } catch (NumberFormatException e) {
+ throw new InvalidFileFormatException(
+ "binary Importer: unknown value where integer expected");
+ }
+ }
+
+ @Override
+ public void initializeBoard(String[] statements) throws UnsupportedOperationException {
+ throw new UnsupportedOperationException("Binary cannot accept text input");
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryType.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryType.java
new file mode 100644
index 000000000..6e3413d7a
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryType.java
@@ -0,0 +1,11 @@
+package edu.rpi.legup.puzzle.binary;
+
+public enum BinaryType {
+ ZERO,
+ ONE,
+ UNKNOWN;
+
+ public int toValue() {
+ return this.ordinal();
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryView.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryView.java
new file mode 100644
index 000000000..b11554f28
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryView.java
@@ -0,0 +1,24 @@
+package edu.rpi.legup.puzzle.binary;
+
+import edu.rpi.legup.controller.BoardController;
+import edu.rpi.legup.model.gameboard.PuzzleElement;
+import edu.rpi.legup.ui.boardview.GridBoardView;
+import java.awt.*;
+
+public class BinaryView extends GridBoardView {
+
+ public BinaryView(BinaryBoard board) {
+ super(new BoardController(), new BinaryController(), board.getDimension());
+
+ for (PuzzleElement puzzleElement : board.getPuzzleElements()) {
+ BinaryCell cell = (BinaryCell) puzzleElement;
+ Point loc = cell.getLocation();
+ BinaryElementView elementView = new BinaryElementView(cell);
+ elementView.setIndex(cell.getIndex());
+ elementView.setSize(elementSize);
+ elementView.setLocation(
+ new Point(loc.x * elementSize.width, loc.y * elementSize.height));
+ elementViews.add(elementView);
+ }
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/elements/BlankTile.java b/src/main/java/edu/rpi/legup/puzzle/binary/elements/BlankTile.java
new file mode 100644
index 000000000..8b1378917
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/binary/elements/BlankTile.java
@@ -0,0 +1 @@
+
diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/elements/NumberTile.java b/src/main/java/edu/rpi/legup/puzzle/binary/elements/NumberTile.java
new file mode 100644
index 000000000..8b1378917
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/binary/elements/NumberTile.java
@@ -0,0 +1 @@
+
diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java
new file mode 100644
index 000000000..e38c6b78d
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java
@@ -0,0 +1,55 @@
+package edu.rpi.legup.puzzle.binary.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.model.rules.DirectRule;
+import edu.rpi.legup.model.tree.TreeNode;
+import edu.rpi.legup.model.tree.TreeTransition;
+import edu.rpi.legup.puzzle.binary.BinaryBoard;
+import edu.rpi.legup.puzzle.binary.BinaryCell;
+
+public class CompleteRowColumnDirectRule extends DirectRule {
+
+ public CompleteRowColumnDirectRule() {
+ super(
+ "BINA-BASC-0003",
+ "Complete Row Column",
+ "If a row/column of length n contains n/2 of a single value, the remaining cells must contain the other value",
+ "edu/rpi/legup/images/binary/rules/CompleteRowColumnDirectRule.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) {
+ BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard();
+ ContradictionRule contraRule = new UnbalancedRowOrColumnContradictionRule();
+ BinaryCell binaryCell = (BinaryCell) puzzleElement;
+ BinaryBoard modified = origBoard.copy();
+ BinaryCell c = (BinaryCell) modified.getPuzzleElement(puzzleElement);
+
+ // System.out.println("ORIG" + binaryCell.getData());
+ // System.out.println("AFTER" + Math.abs(binaryCell.getData() - 1));
+ modified.getPuzzleElement(puzzleElement).setData(binaryCell.getData());
+ System.out.println(contraRule.checkContradictionAt(modified, puzzleElement));
+
+ if (contraRule.checkContradictionAt(modified, puzzleElement) != null) {
+ return null;
+ }
+
+ return "Grouping of Three Ones or Zeros not found";
+ }
+
+ @Override
+ public Board getDefaultBoard(TreeNode node) {
+ return null;
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsOrColumnsContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsOrColumnsContradictionRule.java
new file mode 100644
index 000000000..8b0d88ae4
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsOrColumnsContradictionRule.java
@@ -0,0 +1,55 @@
+package edu.rpi.legup.puzzle.binary.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.binary.BinaryBoard;
+import edu.rpi.legup.puzzle.binary.BinaryCell;
+import edu.rpi.legup.puzzle.binary.BinaryType;
+import java.util.ArrayList;
+
+public class DuplicateRowsOrColumnsContradictionRule extends ContradictionRule {
+ private final String NO_CONTRADICTION_MESSAGE =
+ "Does not contain a contradiction at this index";
+ private final String INVALID_USE_MESSAGE = "Row or column must have a value in each cell";
+
+ public DuplicateRowsOrColumnsContradictionRule() {
+ super(
+ "BINA-CONT-0003",
+ "Duplicate Rows Or Columns",
+ "There must not be two rows or two columns that are duplicates",
+ "edu/rpi/legup/images/binary/rules/DuplicateRowOrColumnContradictionRule.png");
+ }
+
+ @Override
+ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) {
+ BinaryBoard binaryBoard = (BinaryBoard) board;
+ BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement);
+
+ ArrayList row = binaryBoard.getRowTypes(cell.getLocation().y);
+
+ int size = row.size();
+
+ for (int i = 0; i < size; i++) {
+ if (i > cell.getLocation().y) {
+ ArrayList currRow = binaryBoard.getRowTypes(i);
+ if (currRow.equals(row)) {
+ return null;
+ }
+ }
+ }
+
+ ArrayList col = binaryBoard.getColTypes(cell.getLocation().x);
+
+ for (int i = 0; i < size; i++) {
+ if (i > cell.getLocation().x) {
+ ArrayList currCol = binaryBoard.getColTypes(i);
+ if (currCol.equals(col)) {
+ return null;
+ }
+ }
+ }
+
+ return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE;
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneOrZeroCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneOrZeroCaseRule.java
new file mode 100644
index 000000000..70549cd72
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneOrZeroCaseRule.java
@@ -0,0 +1,90 @@
+package edu.rpi.legup.puzzle.binary.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.binary.BinaryBoard;
+import edu.rpi.legup.puzzle.binary.BinaryCell;
+import edu.rpi.legup.puzzle.binary.BinaryType;
+import java.util.ArrayList;
+import java.util.List;
+
+public class OneOrZeroCaseRule extends CaseRule {
+
+ public OneOrZeroCaseRule() {
+ super(
+ "BINA-CASE-0001",
+ "One or Zero",
+ "Each blank cell is either a one or a zero.",
+ "edu/rpi/legup/images/binary/rules/OneOrZeroCaseRule.png");
+ }
+
+ @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.";
+ }
+
+ BinaryCell mod1 = (BinaryCell) case1.getBoard().getModifiedData().iterator().next();
+ BinaryCell mod2 = (BinaryCell) 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.getType() == BinaryType.ZERO && mod2.getType() == BinaryType.ONE)
+ || (mod2.getType() == BinaryType.ZERO && mod1.getType() == BinaryType.ONE))) {
+ return super.getInvalidUseOfRuleMessage()
+ + ": This case rule must an empty white and black cell.";
+ }
+
+ return null;
+ }
+
+ @Override
+ public CaseBoard getCaseBoard(Board board) {
+ BinaryBoard binaryBoard = (BinaryBoard) board.copy();
+ CaseBoard caseBoard = new CaseBoard(binaryBoard, this);
+ binaryBoard.setModifiable(false);
+ for (PuzzleElement element : binaryBoard.getPuzzleElements()) {
+ if (((BinaryCell) element).getType() == BinaryType.UNKNOWN) {
+ caseBoard.addPickableElement(element);
+ }
+ }
+ return caseBoard;
+ }
+
+ @Override
+ public ArrayList getCases(Board board, PuzzleElement puzzleElement) {
+ ArrayList cases = new ArrayList<>();
+ Board case1 = board.copy();
+ PuzzleElement data1 = case1.getPuzzleElement(puzzleElement);
+ data1.setData(BinaryType.ZERO.toValue());
+ case1.addModifiedData(data1);
+ cases.add(case1);
+
+ Board case2 = board.copy();
+ PuzzleElement data2 = case2.getPuzzleElement(puzzleElement);
+ data2.setData(BinaryType.ONE.toValue());
+ case2.addModifiedData(data2);
+ cases.add(case2);
+
+ return cases;
+ }
+
+ @Override
+ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) {
+ return null;
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java
new file mode 100644
index 000000000..2e1e96fa5
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java
@@ -0,0 +1,64 @@
+package edu.rpi.legup.puzzle.binary.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.model.rules.DirectRule;
+import edu.rpi.legup.model.tree.TreeNode;
+import edu.rpi.legup.model.tree.TreeTransition;
+import edu.rpi.legup.puzzle.binary.BinaryBoard;
+import edu.rpi.legup.puzzle.binary.BinaryCell;
+
+public class OneTileGapDirectRule extends DirectRule {
+ private final String INVALID_USE_MESSAGE = "Number at cell is incorrect";
+
+ public OneTileGapDirectRule() {
+ super(
+ "BINA-BASC-0002",
+ "One Tile Gap",
+ "If an empty tile is in between the same value, fill the gap with the other value.",
+ "edu/rpi/legup/images/binary/rules/OneTileGapDirectRule.png");
+ }
+
+ boolean checkLeftRight(BinaryCell c, BinaryBoard board) {
+ int x = c.getLocation().x;
+ int y = c.getLocation().y;
+ return board.getCell(x - 1, y).getType() != c.getType()
+ || board.getCell(x + 1, y).getType() != c.getType();
+ }
+
+ boolean checkUpDown(BinaryCell c, BinaryBoard board) {
+ int x = c.getLocation().x;
+ int y = c.getLocation().y;
+ return board.getCell(x, y - 1).getType() != c.getType()
+ || board.getCell(x, y + 1).getType() != c.getType();
+ }
+
+ @Override
+ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) {
+ BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard();
+ ContradictionRule contraRule = new ThreeAdjacentContradictionRule();
+ BinaryCell binaryCell = (BinaryCell) puzzleElement;
+ BinaryBoard modified = origBoard.copy();
+
+ // System.out.println("ORIG" + binaryCell.getData());
+ // System.out.println("AFTER" + Math.abs(binaryCell.getData() - 1));
+ modified.getPuzzleElement(puzzleElement).setData(Math.abs(binaryCell.getData() - 1));
+
+ PuzzleElement newP = binaryCell;
+
+ System.out.println(contraRule.checkContradictionAt(modified, newP));
+
+ if (contraRule.checkContradictionAt(modified, newP) == null) {
+ return null;
+ }
+ modified.getPuzzleElement(puzzleElement).setData(Math.abs(binaryCell.getData() - 1));
+
+ return "Grouping of Three Ones or Zeros not found";
+ }
+
+ @Override
+ public Board getDefaultBoard(TreeNode node) {
+ return null;
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java
new file mode 100644
index 000000000..dc2f07c8b
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java
@@ -0,0 +1,48 @@
+package edu.rpi.legup.puzzle.binary.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.model.rules.DirectRule;
+import edu.rpi.legup.model.tree.TreeNode;
+import edu.rpi.legup.model.tree.TreeTransition;
+import edu.rpi.legup.puzzle.binary.BinaryBoard;
+import edu.rpi.legup.puzzle.binary.BinaryCell;
+
+public class SurroundPairDirectRule extends DirectRule {
+
+ public SurroundPairDirectRule() {
+ super(
+ "BINA-BASC-0001",
+ "Surround Pair",
+ "If two adjacent tiles have the same value, surround the tiles with the other value.",
+ "edu/rpi/legup/images/binary/rules/SurroundPairDirectRule.png");
+ }
+
+ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) {
+ BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard();
+ ContradictionRule contraRule = new ThreeAdjacentContradictionRule();
+ BinaryCell binaryCell = (BinaryCell) puzzleElement;
+ BinaryBoard modified = origBoard.copy();
+
+ // System.out.println("ORIG" + binaryCell.getData());
+ // System.out.println("AFTER" + Math.abs(binaryCell.getData() - 1));
+ modified.getPuzzleElement(puzzleElement).setData(Math.abs(binaryCell.getData() - 1));
+
+ PuzzleElement newP = binaryCell;
+
+ System.out.println(contraRule.checkContradictionAt(modified, newP));
+
+ if (contraRule.checkContradictionAt(modified, newP) == null) {
+ return null;
+ }
+ modified.getPuzzleElement(puzzleElement).setData(Math.abs(binaryCell.getData() - 1));
+
+ return "Grouping of Three Ones or Zeros not found";
+ }
+
+ @Override
+ public Board getDefaultBoard(TreeNode node) {
+ return null;
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java
new file mode 100644
index 000000000..075642246
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java
@@ -0,0 +1,127 @@
+package edu.rpi.legup.puzzle.binary.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.binary.BinaryBoard;
+import edu.rpi.legup.puzzle.binary.BinaryCell;
+import edu.rpi.legup.puzzle.binary.BinaryType;
+
+public class ThreeAdjacentContradictionRule 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 zero or one";
+
+ public ThreeAdjacentContradictionRule() {
+ super(
+ "BINA-CONT-0001",
+ "Three Adjacent",
+ "There must not be three adjacent zeros or three adjacent ones in a row or column",
+ "edu/rpi/legup/images/binary/rules/ThreeAdjacentContradictionRule.png");
+ }
+
+ @Override
+ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) {
+ BinaryBoard binaryBoard = (BinaryBoard) board;
+ int height = binaryBoard.getHeight();
+ int width = binaryBoard.getWidth();
+
+ BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement);
+ System.out.println("THE CELL IS : " + cell.getType());
+ int cellX = cell.getLocation().x;
+ int cellY = cell.getLocation().y;
+ BinaryCell oneUp = null;
+ BinaryCell oneDown = null;
+ BinaryCell oneForward = null;
+ BinaryCell oneBackward = null;
+ BinaryCell twoUp = null;
+ BinaryCell twoDown = null;
+ BinaryCell twoForward = null;
+ BinaryCell twoBackward = null;
+ if (binaryBoard.getCell(cellX, cellY + 1) != null) {
+ oneUp = binaryBoard.getCell(cellX, cellY + 1);
+ }
+ if (binaryBoard.getCell(cellX, cellY - 1) != null) {
+ oneDown = binaryBoard.getCell(cellX, cellY - 1);
+ }
+ if (binaryBoard.getCell(cellX + 1, cellY) != null) {
+ oneForward = binaryBoard.getCell(cellX + 1, cellY);
+ }
+ if (binaryBoard.getCell(cellX - 1, cellY) != null) {
+ oneBackward = binaryBoard.getCell(cellX - 1, cellY);
+ }
+ if (binaryBoard.getCell(cellX, cellY + 2) != null) {
+ twoUp = binaryBoard.getCell(cellX, cellY + 2);
+ }
+ if (binaryBoard.getCell(cellX, cellY - 2) != null) {
+ twoDown = binaryBoard.getCell(cellX, cellY - 2);
+ }
+ if (binaryBoard.getCell(cellX + 2, cellY) != null) {
+ twoForward = binaryBoard.getCell(cellX + 2, cellY);
+ }
+ if (binaryBoard.getCell(cellX - 2, cellY) != null) {
+ twoBackward = binaryBoard.getCell(cellX - 2, cellY);
+ }
+
+ if (cell.getType() == BinaryType.ONE || cell.getType() == BinaryType.ZERO) {
+ if (twoBackward != null
+ && oneBackward != null
+ && twoBackward.getType() != BinaryType.UNKNOWN
+ && oneBackward.getType() != BinaryType.UNKNOWN) {
+ if (twoBackward.getType() == cell.getType()
+ && oneBackward.getType() == cell.getType()) {
+ System.out.println("1");
+ return null;
+ }
+ }
+ if (twoForward != null
+ && oneForward != null
+ && twoForward.getType() != BinaryType.UNKNOWN
+ && oneForward.getType() != BinaryType.UNKNOWN) {
+ if (twoForward.getType() == cell.getType()
+ && oneForward.getType() == cell.getType()) {
+ System.out.println("2");
+ return null;
+ }
+ }
+ if (twoDown != null
+ && oneDown != null
+ && twoDown.getType() != BinaryType.UNKNOWN
+ && oneDown.getType() != BinaryType.UNKNOWN) {
+ if (twoDown.getType() == cell.getType() && oneDown.getType() == cell.getType()) {
+ System.out.println("3");
+ return null;
+ }
+ }
+ if (twoUp != null
+ && oneUp != null
+ && twoUp.getType() != BinaryType.UNKNOWN
+ && oneUp.getType() != BinaryType.UNKNOWN) {
+ if (twoUp.getType() == cell.getType() && oneUp.getType() == cell.getType()) {
+ System.out.println("4");
+ return null;
+ }
+ }
+ if (oneBackward != null
+ && oneForward != null
+ && oneBackward.getType() != BinaryType.UNKNOWN
+ && oneForward.getType() != BinaryType.UNKNOWN) {
+ if (oneBackward.getType() == cell.getType()
+ && oneForward.getType() == cell.getType()) {
+ System.out.println("5");
+ return null;
+ }
+ }
+ if (oneUp != null
+ && oneDown != null
+ && oneUp.getType() != BinaryType.UNKNOWN
+ && oneDown.getType() != BinaryType.UNKNOWN) {
+ if (oneUp.getType() == cell.getType() && oneDown.getType() == cell.getType()) {
+ System.out.println("6");
+ return null;
+ }
+ }
+ }
+ return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE;
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java
new file mode 100644
index 000000000..5089b3b5f
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java
@@ -0,0 +1,68 @@
+package edu.rpi.legup.puzzle.binary.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.binary.BinaryBoard;
+import edu.rpi.legup.puzzle.binary.BinaryCell;
+import edu.rpi.legup.puzzle.binary.BinaryType;
+import java.util.Set;
+
+public class UnbalancedRowOrColumnContradictionRule extends ContradictionRule {
+
+ private final String NO_CONTRADICTION_MESSAGE =
+ "Does not contain a contradiction at this index";
+ private final String INVALID_USE_MESSAGE = "Row or column must have a value in each cell";
+
+ public UnbalancedRowOrColumnContradictionRule() {
+ super(
+ "BINA-CONT-0002",
+ "Unbalanced Row Or Column",
+ "Each row or column must contain an equal number of zeros and ones",
+ "edu/rpi/legup/images/binary/rules/UnbalancedRowColumnContradictionRule.png");
+ }
+
+ @Override
+ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) {
+ BinaryBoard binaryBoard = (BinaryBoard) board;
+
+ BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement);
+ Set row = binaryBoard.getRowCells(cell.getLocation().y);
+
+ int size = row.size();
+ int rowNumZeros = 0;
+ int rowNumOnes = 0;
+
+ for (BinaryCell item : row) {
+ if (item.getType() == BinaryType.ZERO) {
+ rowNumZeros++;
+ } else if (item.getType() == BinaryType.ONE) {
+ rowNumOnes++;
+ }
+ }
+
+ if (rowNumZeros == size / 2 && rowNumOnes == size / 2) {
+ return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE;
+ }
+
+ Set col = binaryBoard.getCol(cell.getLocation().x);
+
+ size = col.size();
+ int colNumZeros = 0;
+ int colNumOnes = 0;
+
+ for (BinaryCell item : col) {
+ if (item.getType() == BinaryType.ZERO) {
+ colNumZeros++;
+ } else if (item.getType() == BinaryType.ONE) {
+ colNumOnes++;
+ }
+ }
+
+ if (colNumZeros == size / 2 && colNumOnes == size / 2) {
+ return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE;
+ }
+
+ return null;
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/binary_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/binary/rules/binary_reference_sheet.txt
new file mode 100644
index 000000000..c8cb0d1b9
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/binary_reference_sheet.txt
@@ -0,0 +1,9 @@
+BINA-BASC-0001 : SurroundPairDirectRule
+BINA-BASC-0002 : OneTileGapDirectRule
+BINA-BASC-0003 : CompleteRowColumnDirectRule
+
+BINA-CONT-0001 : ThreeAdjacentContradictionRule
+BINA-CONT-0002 : UnbalancedRowOrColumnContradictionRule
+BINA-CONT-0003 : DuplicateRowsOrColumnsContradictionRule
+
+BINA-CASE-0001 : OneOrZeroCaseRule
\ No newline at end of file
diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/CompleteRowColumnDirectRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/CompleteRowColumnDirectRule.png
new file mode 100644
index 000000000..a74654d43
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/binary/rules/CompleteRowColumnDirectRule.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/DuplicateRowOrColumnContradictionRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/DuplicateRowOrColumnContradictionRule.png
new file mode 100644
index 000000000..214aa5348
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/binary/rules/DuplicateRowOrColumnContradictionRule.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/OneOrZeroCaseRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/OneOrZeroCaseRule.png
new file mode 100644
index 000000000..73072f2ce
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/binary/rules/OneOrZeroCaseRule.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/OneTileGapDirectRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/OneTileGapDirectRule.png
new file mode 100644
index 000000000..b68f67e44
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/binary/rules/OneTileGapDirectRule.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/SurroundPairDirectRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/SurroundPairDirectRule.png
new file mode 100644
index 000000000..67a4e47f3
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/binary/rules/SurroundPairDirectRule.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/ThreeAdjacentContradictionRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/ThreeAdjacentContradictionRule.png
new file mode 100644
index 000000000..862408b63
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/binary/rules/ThreeAdjacentContradictionRule.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/UnbalancedRowColumnContradictionRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/UnbalancedRowColumnContradictionRule.png
new file mode 100644
index 000000000..029bd12ac
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/binary/rules/UnbalancedRowColumnContradictionRule.png differ
diff --git a/src/main/resources/edu/rpi/legup/legup/config b/src/main/resources/edu/rpi/legup/legup/config
index f16226b93..b221eb653 100644
--- a/src/main/resources/edu/rpi/legup/legup/config
+++ b/src/main/resources/edu/rpi/legup/legup/config
@@ -4,6 +4,10 @@
qualifiedClassName="edu.rpi.legup.puzzle.battleship.Battleship"
fileType=".xml"
fileCreationDisabled="true"/>
+