konkon / Cage.java
Cage.java
Raw
import javafx.geometry.Pos;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;

public class Cage {

    private ArrayList<Cell> cells = new ArrayList<>();
    private HashMap<Integer, Cell> cellMap = new HashMap<>();
    private int target;
    private char operator;
    private GameManager manager;
    public Text idOverlay;

    Cage(GameManager manager, CageConfig cageConfig) {
        this.manager = manager;
        this.target = cageConfig.target;
        this.operator = cageConfig.operator;

        // adds each cell to it's list of cages from the config
        for (int cellID : cageConfig.cellIDs) {
            this.cells.add(new Cell(manager, cellID, this));
        }

        // puts them into a map so they can be found by id
        for (Cell cell : cells) {
            cellMap.put(cell.getCellID(), cell);
        }

        // operator s stands for singleton
        // constructs the target/operator label for the cage
        if (operator != 's') {
            idOverlay = new Text(Integer.toString(target) + operator);
        } else {
            idOverlay = new Text(Integer.toString(target));
        }
        idOverlay.setFont(Font.font("Courier New", FontWeight.BOLD, 15));
        StackPane.setAlignment(idOverlay, Pos.TOP_LEFT);
        Cell left = getTopLeft();
        left.getChildren().add(idOverlay);

    }

    // sets borders to be thinner between cells in the same cage by iterating over all cells twice
    void setBorders() {
        for (Cell cell : cells) {
            double top = 1.5, bottom = 1.5, left = 1.5, right = 1.5;
            for (Cell adjCell : cells) {
                if (adjCell.getCellID() == cell.getCellID() + 1) {
                    right = 0.1;
                } else if (adjCell.getCellID() == cell.getCellID() - 1) {
                    left = 0.1;
                } else if (adjCell.getCellID() == (cell.getCellID() + this.manager.getN())) {
                    bottom = 0.1;
                } else if (adjCell.getCellID() == (cell.getCellID() - this.manager.getN())) {
                    top = 0.1;
                }
            }
            BorderStroke borderStroke = new BorderStroke(Color.BLACK, BorderStrokeStyle.SOLID,
                    new CornerRadii(0.1), new BorderWidths(top, right, bottom, left));
            cell.setBorder(new Border(borderStroke));
        }
    }

    // gets the top left cell in a cage to put the label on
    Cell getTopLeft() {
        Cell topLeft = null;
        int highestID = Integer.MAX_VALUE;
        for (Cell cell : cells) {
            if (cell.getCellID() < highestID) {
                highestID = cell.getCellID();
                topLeft = cell;
            }
        }
        return topLeft;
    }

    // checks if itself is filled correctly
    // maths checks return max value because it was a number that is unlikely to appear otherwise given its hard capped at 8*8
    // because i wanted to use the same function for mistake and victory checking but mistake checking
    // needed to ignore empty cells
    public boolean isFilledCorrectly(boolean victoryCheck) {
        if (this.operator == 'x' || this.operator == '*') {
            return multiplyCells(victoryCheck).equals(this.target) || (!victoryCheck && multiplyCells(false) == Integer.MAX_VALUE);
        } else if (this.operator == '+') {
            return addCells(victoryCheck).equals(this.target) || (!victoryCheck && addCells(false) == Integer.MAX_VALUE);
        } else if (this.operator == '-') {
            return subtractCells(victoryCheck).equals(this.target) || (!victoryCheck && subtractCells(false) == Integer.MAX_VALUE);
        } else if (this.operator == '/' || this.operator == '÷') {
            Double total = divideCells(victoryCheck);
            if (total % 1 == 0) {
                return total.intValue() == this.target || (!victoryCheck && divideCells(false) == Double.MAX_VALUE);
            }
            return false;
        } else {
            return cells.get(0).getCurrentValue().equals(this.target);
        }
    }

    public Integer subtractCells(boolean victoryCheck) {
        ArrayList<Integer> cellValues = new ArrayList<>();
        for (int i = 0; i < cells.size(); i++) {
            if (cells.get(i).getCurrentValue() == 0 && !victoryCheck) {
                return Integer.MAX_VALUE;
            }
            cellValues.add(cells.get(i).getCurrentValue());
        }

        Collections.sort(cellValues);
        Collections.reverse(cellValues);

        int total = cellValues.get(0);
        for (int i : cellValues.subList(1, cellValues.size())) {
            total -= i;
        }
        return total;
    }

    public Integer multiplyCells(boolean victoryCheck) {
        Integer flag = 1;
        for (Cell cell : cells) {
            if (cell.getCurrentValue() == 0 && !victoryCheck) {
                return Integer.MAX_VALUE;
            }
            flag = flag * cell.getCurrentValue();
        }
        return flag;
    }

    public Integer addCells(boolean victoryCheck) {
        Integer flag = 0;
        for (Cell cell : cells) {
            if (cell.getCurrentValue() == 0 && !victoryCheck) {
                return Integer.MAX_VALUE;
            }
            flag += cell.getCurrentValue();
        }
        return flag;
    }

    public Double divideCells(boolean victoryCheck) {
        ArrayList<Integer> cellValues = new ArrayList<>();
        for (int i = 0; i < cells.size(); i++) {
            if (cells.get(i).getCurrentValue() == 0 && !victoryCheck) {
                return Double.MAX_VALUE;
            }
            cellValues.add(cells.get(i).getCurrentValue());
        }

        Collections.sort(cellValues);
        Collections.reverse(cellValues);

        double total = cellValues.get(0);
        for (int i : cellValues.subList(1, cellValues.size())) {
            total = total / i;
        }
        return total;
    }

    public ArrayList<Cell> getCells() {
        return this.cells;
    }

    public HashMap<Integer, Cell> getCellMap() {
        return this.cellMap;
    }

    public char getOperator() {
        return this.operator;
    }

    public int getTarget() {
        return this.target;
    }
}