Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Discontinuous Mercury Rule + Misc. behind the scenes changes #739

Merged
merged 8 commits into from
Feb 27, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,93 @@

import edu.rpi.legup.model.gameboard.GridBoard;
import edu.rpi.legup.model.gameboard.PuzzleElement;
import edu.rpi.legup.puzzle.thermometer.elements.Vial;

import java.util.ArrayList;

import static edu.rpi.legup.puzzle.thermometer.elements.Vial.verifyVial;

public class ThermometerBoard extends GridBoard{

//an array containing all of our vials on the board
private ArrayList<Vial> vials;

//representations of the number requirements along rows and columns of the board
private ArrayList<Integer> colNumbers;
private ArrayList<Integer> rowNumbers;

//constructors for the boards and variables
public ThermometerBoard(int width, int height){
super(width, height);
}

//filling the arrays with zeros so they can be properly updated later
colNumbers = new ArrayList<>();
for (int i = 0; i < width; i++) {
colNumbers.add(0);
}
rowNumbers = new ArrayList<>();
for (int i = 0; i < height; i++) {
rowNumbers.add(0);
}

vials = new ArrayList<>();
}
public ThermometerBoard(int size){
super(size, size);

//filling the arrays with zeros so they can be properly updated later
colNumbers = new ArrayList<>();
rowNumbers = new ArrayList<>();
for (int i = 0; i < size; i++) {
colNumbers.add(0);
rowNumbers.add(0);
}

vials = new ArrayList<>();
}

//setters and accessors for our array of vials
public boolean addVial(ThermometerCell headCell, ThermometerCell tipCell) {
if(verifyVial(headCell, tipCell, this)) {
vials.add(new Vial(headCell, tipCell, this));
return true;
}
return false;
}
public ArrayList<Vial> getVials() {
return vials;
}


//our getters 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.set(row, 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()){
rowNumbers.set(col, num);
return true;
}
return false;
}

//basic accessors, probably fine as is
public int getRowNumber(int row){
return rowNumbers.get(row);
}
public int getColNumber(int col){
return colNumbers.get(col);
}


@Override
public ThermometerCell getCell(int x, int y){
return (ThermometerCell) super.getCell(x, y);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,27 @@ public void changeCell(MouseEvent e, PuzzleElement 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 {
}
else {
if (cell.getData() == ThermometerFill.EMPTY.ordinal()) {
data.setData(ThermometerFill.FILLED.ordinal());
} else if (cell.getData() == ThermometerFill.FILLED.ordinal()) {
}
else if (cell.getData() == ThermometerFill.FILLED.ordinal()) {
data.setData(ThermometerFill.BLOCKED.ordinal());
} else {
}
else {
data.setData(ThermometerFill.EMPTY.ordinal());
}
}
} else if (e.getButton() == MouseEvent.BUTTON2) {
}
else if (e.getButton() == MouseEvent.BUTTON2) {
if (cell.getData() == ThermometerFill.EMPTY.ordinal()) {
data.setData(ThermometerFill.BLOCKED.ordinal());
} else if (cell.getData() == ThermometerFill.BLOCKED.ordinal()) {
}
else if (cell.getData() == ThermometerFill.BLOCKED.ordinal()) {
data.setData(ThermometerFill.FILLED.ordinal());
} else {
}
else {
data.setData(ThermometerFill.EMPTY.ordinal());
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,51 +28,63 @@ public void drawElement(Graphics2D graphics2D) {
graphics2D.setStroke(new BasicStroke(1));
graphics2D.setColor(Color.BLACK);
graphics2D.fillRect(location.x, location.y, size.width, size.height);
} else if (fill == ThermometerFill.EMPTY) {
}
else if (fill == ThermometerFill.EMPTY) {
graphics2D.setStroke(new BasicStroke(1));
graphics2D.setColor(Color.WHITE);
graphics2D.fillRect(location.x, location.y, size.width, size.height);
} else if (fill == ThermometerFill.BLOCKED){
}
else if (fill == ThermometerFill.BLOCKED){
graphics2D.setStroke(new BasicStroke(1));
graphics2D.setColor(Color.BLUE);
graphics2D.fillRect(location.x, location.y, size.width, size.height);
}else{
}
else{
System.out.println("ZEV IS BAD AT DEV");
}

} else if (type == ThermometerType.SHAFT) {
}
else if (type == ThermometerType.SHAFT) {
if(fill == ThermometerFill.FILLED){
graphics2D.setStroke(new BasicStroke(1));
graphics2D.setColor(Color.BLACK);
graphics2D.fillRect(location.x, location.y, size.width, size.height);
} else if (fill == ThermometerFill.EMPTY) {
}
else if (fill == ThermometerFill.EMPTY) {
graphics2D.setStroke(new BasicStroke(1));
graphics2D.setColor(Color.WHITE);
graphics2D.fillRect(location.x, location.y, size.width, size.height);
} else if (fill == ThermometerFill.BLOCKED){
}
else if (fill == ThermometerFill.BLOCKED){
graphics2D.setStroke(new BasicStroke(1));
graphics2D.setColor(Color.BLUE);
graphics2D.fillRect(location.x, location.y, size.width, size.height);
}else{
}
else{
System.out.println("ZEV IS BAD AT DEV");
}
} else if (type == ThermometerType.TIP) {
}
else if (type == ThermometerType.TIP) {
if(fill == ThermometerFill.FILLED){
graphics2D.setStroke(new BasicStroke(1));
graphics2D.setColor(Color.BLACK);
graphics2D.fillRect(location.x, location.y, size.width, size.height);
} else if (fill == ThermometerFill.EMPTY) {
}
else if (fill == ThermometerFill.EMPTY) {
graphics2D.setStroke(new BasicStroke(1));
graphics2D.setColor(Color.WHITE);
graphics2D.fillRect(location.x, location.y, size.width, size.height);
} else if (fill == ThermometerFill.BLOCKED){
}
else if (fill == ThermometerFill.BLOCKED){
graphics2D.setStroke(new BasicStroke(1));
graphics2D.setColor(Color.BLUE);
graphics2D.fillRect(location.x, location.y, size.width, size.height);
}else{
}
else{
System.out.println("ZEV IS BAD AT DEV");
}
} else if (type == ThermometerType.UNKNOWN) {
}
else{
System.out.println("ZEV IS DOUBLE BAD AT DEV");
}
}
Expand Down
136 changes: 136 additions & 0 deletions src/main/java/edu/rpi/legup/puzzle/thermometer/elements/Vial.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package edu.rpi.legup.puzzle.thermometer.elements;

import edu.rpi.legup.puzzle.thermometer.ThermometerCell;
import edu.rpi.legup.puzzle.thermometer.ThermometerBoard;
import edu.rpi.legup.puzzle.thermometer.ThermometerFill;
import edu.rpi.legup.puzzle.thermometer.ThermometerType;
import edu.rpi.legup.model.elements.PlaceableElement;

import java.awt.*;
import java.util.ArrayList;

import static java.lang.Math.*;

public class Vial {
private ArrayList<ThermometerCell> cells;

public Vial(ThermometerCell headCell, ThermometerCell tipCell, ThermometerBoard board) {
cells = new ArrayList<>();
fillData(headCell, tipCell, 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(ThermometerCell headCell, ThermometerCell tipCell, ThermometerBoard board) {
//shorthand for useful variables
int headX = (int) headCell.getLocation().getX();
int headY = (int) headCell.getLocation().getY();
int tipX = (int) tipCell.getLocation().getX();
int tipY = (int) tipCell.getLocation().getY();

//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, board);
for (int i = headY + 1; i < tipY - 1; i++) {
addCell(headX, i, ThermometerType.SHAFT, board);
}
addCell(tipX, tipY, ThermometerType.TIP, board);
}
else if (tipY < headY) {
addCell(headX, headY, ThermometerType.HEAD, board);
for (int i = headY - 1; i > tipY; i--) {
addCell(headX, i, ThermometerType.SHAFT, board);
}
addCell(tipX, tipY, ThermometerType.TIP, board);
}
else if (headX < tipX){
addCell(headX, headY, ThermometerType.HEAD, board);
for (int i = headX + 1; i < tipX - 1; i++) {
addCell(i, headY, ThermometerType.SHAFT, board);
}
addCell(tipX, tipY, ThermometerType.TIP, board);
}
else{
addCell(headX, headY, ThermometerType.HEAD, board);
for (int i = headX - 1; i > tipX; i--) {
addCell(i, headY, ThermometerType.SHAFT, board);
}
addCell(tipX, tipY, ThermometerType.TIP, board);
}

}

//helper function for adding a single cell
private void addCell(int x, int y, ThermometerType t, ThermometerBoard board){

//this very likely is not updating the data in the way we want it to
board.getCell(x, y).setData(t.ordinal());
cells.add(board.getCell(x, y));
}

//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;
}

//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;
}


//used before calling the constructor to make sure the vial we are attempting to add is valid
public static boolean verifyVial(ThermometerCell headCell, ThermometerCell tipCell, ThermometerBoard board) {
//shorthand for useful variables
int headX = (int) headCell.getLocation().getX();
int headY = (int) headCell.getLocation().getY();
int tipX = (int) tipCell.getLocation().getX();
int tipY = (int) tipCell.getLocation().getY();


//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 unclaimed
for (int i = top; i < bottom; i++) {
if(board.getCell(headX, i).getType() != ThermometerType.UNKNOWN) return false;
}
}
else if (headY == tipY) {
//finding start and end of Vial
int top = min(headX, tipX);
int bottom = max(headX, tipX);

//verifying that every cell along path is currently unclaimed
for (int i = top; i < bottom; i++) {
if(board.getCell(i, headY).getType() != ThermometerType.UNKNOWN) return false;
}
}
else{
//thermometer does not line up along a single axis
return false;
}
return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
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.elements.Vial;

import java.util.ArrayList;

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("DiscontinuousMercury",
"Discontinuous Mercury",
"A vial has a filled cell after an empty or blocked cell",
null);
}


//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<Vial> vials = thermometerBoard.getVials();

//finding out which vial contains the specified cell
for (int i = 0; i < vials.size(); i++) {
Vial vial = vials.get(i);
//if a vial contains the clicked on cell
//checking if the vial has a break in the flow
if(vial.containsCell(cell)){
if(vial.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;
}
}