konkon / Generator.java
Generator.java
Raw
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Random;

public class Generator {

    public static void main(String[] args) {
        System.out.println(Generator.generate(5));
    }

    public static String generate(int width) {
        int[][] board = new int[width][width];
        for (int[] row: board) {
            Arrays.fill(row, 0);
        }
        fillBoard(board, 0, 0, width);
        ArrayList<ArrayList<Integer>> cages = generateCages(board, width);
        StringBuilder cageConfig = new StringBuilder();

        for(ArrayList<Integer> cage : cages) {
            int target = 0;
            char operator;

            if(cage.size() == 1) {
                target = getValueFromBoard(cage.get(0), board);
                operator = 's';
            } else {
                ArrayList<Integer> numbersInCage = new ArrayList<>();
                for(int x : cage) {
                    numbersInCage.add(getValueFromBoard(x, board));
                }
                int divCheck = checkDivision(numbersInCage);
                int subCheck = checkSubtraction(numbersInCage);
                operator = chooseOperator(divCheck, subCheck);
                if(operator == '÷') {
                    target = divCheck;
                } else if(operator == '-') {
                    target = subCheck;
                } else if(operator == '+') {
                    for(int i : numbersInCage) {
                        target += i;
                    }
                } else if(operator == 'x') {
                    target = 1;
                    for(int i : numbersInCage) {
                        target *= i;
                    }
                }
            }
            if(operator != 's') {
                cageConfig.append(target);
                cageConfig.append(operator);
                cageConfig.append(" ");
            } else {
                cageConfig.append(target).append(" ");
            }
            String cellIDS = cage.toString().substring(1, cage.toString().length() - 1);
            cellIDS = cellIDS.replaceAll("\\s+", "");
            cageConfig.append(cellIDS).append("\n");
        }
        return cageConfig.toString();
    }

    public static char chooseOperator(int divCheck, int subCheck) {
        Random r = new Random();
        int divChance = 4, subChance = 4;
        if(divCheck <= 0) {
            divChance = 0;
        }
        if(subCheck <= 0) {
            subChance = 0;
        }
        subChance += divChance;
        double addChance = ((10.0 - subChance)/2) + subChance;
        int opChoice = r.nextInt(11);
        if(opChoice < divChance) {
            return '÷';
        } else if(opChoice < subChance) {
            return '-';
        } else if(opChoice < addChance) {
            return '+';
        } else {
            return 'x';
        }
    }

    public static int checkSubtraction(ArrayList<Integer> cageValues) {
        Collections.sort(cageValues);
        Collections.reverse(cageValues);
        int total = cageValues.get(0);
        for (int i : cageValues.subList(1, cageValues.size())) {
            total -= i;
        }
        return total;
    }

    public static int checkDivision(ArrayList<Integer> cageValues) {
        Collections.sort(cageValues);
        Collections.reverse(cageValues);
        double total = (double) cageValues.get(0);
        for (int i : cageValues.subList(1, cageValues.size())) {
            total = total / i;
        }
        if ((total == Math.floor(total)) && !Double.isInfinite(total)) {
            return (int) total;
        } else {
            return -1;
        }
    }

    public static int getValueFromBoard(int cellID, int[][] board) {
        cellID -= 1;
        int x = cellID % board.length;
        int y = (cellID - x)/board.length;
        return board[x][y];
    }

    public static ArrayList<ArrayList<Integer>> generateCages(int[][] board, int width) {
        Random r = new Random();
        ArrayList<Integer> untakenCellIDs = new ArrayList<>();
        ArrayList<ArrayList<Integer>> cages = new ArrayList<>();
        for (int i = 1; i < (width * width) + 1; i++) {
            untakenCellIDs.add(i);
        }

        while(!untakenCellIDs.isEmpty()) {
            ArrayList<Integer> tempCage = new ArrayList<>();
            int cellID = getCell(untakenCellIDs);
            int cageSize = getCageSize(untakenCellIDs.size());
            tempCage.add(cellID);
            while(tempCage.size() < cageSize) {
                ArrayList<Integer> neighbours = getNeighbours(board, untakenCellIDs, cellID);
                if(neighbours.size() > 0) {
                    tempCage.add(neighbours.get(0));
                    untakenCellIDs.remove(Integer.valueOf(neighbours.get(0)));
                } else {
                    cellID = tempCage.get(r.nextInt(tempCage.size()));
                    cageSize -= 1;
                }
            }
            cages.add(tempCage);
        }
        return cages;
    }

    public static ArrayList<Integer> getNeighbours(int[][] board, ArrayList<Integer> untakenCells, int cellID) {
        ArrayList<Integer> neighbours = new ArrayList<>();
        for(int cell : untakenCells) {
            if(checkIfCellsAreAdjacent(cell, cellID, board)) {
                neighbours.add(cell);
            }
        }
        return neighbours;
    }

    public static int getCageSize(int untakenCellArraySize) {
        Random r = new Random();
        int chance = r.nextInt(10);
        if(untakenCellArraySize == 1) {
            return 1;
        } else if(untakenCellArraySize == 2 || chance < 4) {
            return 2;
        } else if(untakenCellArraySize == 3 || chance < 7) {
            return 3;
        } else {
            return 4;
        }
    }

    public static int getCell(ArrayList<Integer> untakenCells) {
        Random r = new Random();
        int index = r.nextInt(untakenCells.size());
        int cellID = untakenCells.get(index);
        untakenCells.remove(index);
        return cellID;
    }

    public static boolean checkIfCellsAreAdjacent(int unclaimedCell, int cellInCage, int[][] board) {
        return unclaimedCell == cellInCage + board.length || unclaimedCell == cellInCage - board.length
                || (unclaimedCell == cellInCage + 1 && cellInCage % board.length != 0)
                || (unclaimedCell == cellInCage - 1 && unclaimedCell % board.length != 0);
    }

    public static boolean fillBoard(int[][] board, int x, int y, int width) {
        if(x+1 > width && y+1 == width) {
            return true;
        }
        if(x + 1 > width) {
            x -= width;
            y += 1;
        }
        ArrayList<Integer> values = new ArrayList<>();
        for(int i=1; i<width + 1; i++) {
            values.add(i);
        }
        Collections.shuffle(values);
        for(int value : values) {
            if(!isInRowOrColumn(board, x, y, value, width)) {
                board[x][y] = value;
                if(fillBoard(board, x + 1, y, width)) {
                    return true;
                }
            }
        }
        board[x][y] = 0;
        return false;
    }

    public static boolean isInRowOrColumn(int[][] board, int x, int y, int value, int width) {
        for(int i=0; i<width; i++) {
            if(board[x][i] == value && board[x][i] != 0) {
                return true;
            }
            if(board[i][y] == value && board[i][y] != 0) {
                return true;
            }
        }
        return false;
    }

}