import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; import java.util.regex.Pattern; public class CrossMath { static class Operation { ArrayList<String> parameters; String result; public Operation(ArrayList<String> parameters, String result) { this.parameters = parameters; this.result = result; } @Override public String toString() { return "Operation [" + parameters + ", =" + result + "]"; } public int unknownAmmount(HashMap<String, Integer> solvedUnkowns) { int ammount = 0; final String REGEX = "^((-)?[0-9]+)|([-+x/])$"; for (String str : parameters) { if (!str.matches(REGEX) && !solvedUnkowns.containsKey(str)) { ammount++; } } if (!result.matches(REGEX) && !solvedUnkowns.containsKey(result)) { ammount++; } return ammount; } public void calculateUnkown(HashMap<String, Integer> solvedUnkowns) { for(int position=0;position<this.parameters.size();position++) { String param = this.parameters.get(position); if (solvedUnkowns.containsKey(param)) { this.parameters.set(position, Integer.toString(solvedUnkowns.get(param))); } } String resultVar = result; if (solvedUnkowns.containsKey(resultVar)) { result = Integer.toString(solvedUnkowns.get(resultVar)); } if(result.matches("[A-Z]+")) { int resultUnknown=0; switch(this.parameters.get(1)) { case "+": resultUnknown = Integer.parseInt(this.parameters.get(0))+Integer.parseInt(this.parameters.get(2)); break; case "-": resultUnknown = Integer.parseInt(this.parameters.get(0))-Integer.parseInt(this.parameters.get(2)); break; case "*": resultUnknown = Integer.parseInt(this.parameters.get(0))*Integer.parseInt(this.parameters.get(2)); break; case "/": resultUnknown = Integer.parseInt(this.parameters.get(0))/Integer.parseInt(this.parameters.get(2)); break; default: throw new IllegalArgumentException("Comando desconocido: "); } solvedUnkowns.put(result, resultUnknown); }else if(this.parameters.get(0).matches("[A-Z]+")){ int resultUnknown=0; switch(this.parameters.get(1)) { case "+": resultUnknown = Integer.parseInt(result)-Integer.parseInt(this.parameters.get(2)); break; case "-": resultUnknown = Integer.parseInt(this.parameters.get(2))+Integer.parseInt(result); break; case "*": resultUnknown = Integer.parseInt(result)/Integer.parseInt(this.parameters.get(2)); break; case "/": resultUnknown = Integer.parseInt(result)*Integer.parseInt(this.parameters.get(2)); break; default: throw new IllegalArgumentException("Comando desconocido: "); } solvedUnkowns.put(this.parameters.get(0), resultUnknown); }else if(this.parameters.get(2).matches("[A-Z]+")){ int resultUnknown=0; switch(this.parameters.get(1)) { case "+": resultUnknown = Integer.parseInt(result)-Integer.parseInt(this.parameters.get(0)); break; case "-": resultUnknown = Integer.parseInt(this.parameters.get(0))-Integer.parseInt(result); break; case "*": resultUnknown = Integer.parseInt(result)/Integer.parseInt(this.parameters.get(0)); break; case "/": resultUnknown = Integer.parseInt(this.parameters.get(0))/Integer.parseInt(result); break; default: throw new IllegalArgumentException("Comando desconocido: "); } solvedUnkowns.put(this.parameters.get(2), resultUnknown); } } } public static String[][] solve(String[][] board) { HashMap<String, Integer> solvedUnkowns = new HashMap<String, Integer>(); LinkedList<Operation> operations = new LinkedList<CrossMath.Operation>(); for (int row = 0; row < board.length; row += 2) { ArrayList<String> parameters = new ArrayList<String>(); for (int col = 0; col < board[row].length; col++) { if ("=".equals(board[row][col])) { operations.add(new Operation(parameters, board[row][col+1])); parameters = new ArrayList<String>(); } else { parameters.add(board[row][col]); } } } for (int col = 0; col < board[0].length; col += 2) { ArrayList<String> parameters = new ArrayList<String>(); for (int row = 0; row < board.length; row++) { if ("=".equals(board[row][col])) { operations.add(new Operation(parameters, board[row+1][col])); parameters = new ArrayList<String>(); } else { parameters.add(board[row][col]); } } } int cont = 0; while (0 < operations.size()) { Operation op = operations.pollFirst(); switch (op.unknownAmmount(solvedUnkowns)) { case 0: cont = 0; break; case 1: op.calculateUnkown(solvedUnkowns); cont = 0; break; default: operations.addLast(op); cont++; break; } if (operations.size() <= cont) { String[][] res = new String[5][5]; for(int i = 0; i < board.length; i++) { for(int k = 0; k < board[i].length; k++) { if(board[i][k].matches("[A-Z]")) { res[i][k] = String.valueOf(solvedUnkowns.get(board[i][k])); }else { res[i][k] = board[i][k]; } } } return res; } } return null; } }
package com.cruci.cruci;- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.LinkedList;
- import java.util.regex.Pattern;
- public class CrossMath {
- static class Operation {
- ArrayList<String> parameters;
- String result;
- public Operation(ArrayList<String> parameters, String result) {
- this.parameters = parameters;
- this.result = result;
- }
- @Override
- public String toString() {
- return "Operation [" + parameters + ", =" + result + "]";
- }
- public int unknownAmmount(HashMap<String, Integer> solvedUnkowns) {
- int ammount = 0;
- final String REGEX = "^((-)?[0-9]+)|([-+x/])$";
- for (String str : parameters) {
- if (!str.matches(REGEX) && !solvedUnkowns.containsKey(str)) {
- ammount++;
- }
- }
- if (!result.matches(REGEX) && !solvedUnkowns.containsKey(result)) {
- ammount++;
- }
- return ammount;
- }
- public void calculateUnkown(HashMap<String, Integer> solvedUnkowns) {
- for(int position=0;position<this.parameters.size();position++) {
- String param = this.parameters.get(position);
- if (solvedUnkowns.containsKey(param)) {
- this.parameters.set(position, Integer.toString(solvedUnkowns.get(param)));
- }
- }
- String resultVar = result;
- if (solvedUnkowns.containsKey(resultVar)) {
- result = Integer.toString(solvedUnkowns.get(resultVar));
- }
- if(result.matches("[A-Z]+")) {
- int resultUnknown=0;
- switch(this.parameters.get(1)) {
- case "+":
- resultUnknown = Integer.parseInt(this.parameters.get(0))+Integer.parseInt(this.parameters.get(2));
- break;
- case "-":
- resultUnknown = Integer.parseInt(this.parameters.get(0))-Integer.parseInt(this.parameters.get(2));
- break;
- case "*":
- resultUnknown = Integer.parseInt(this.parameters.get(0))*Integer.parseInt(this.parameters.get(2));
- break;
- case "/":
- resultUnknown = Integer.parseInt(this.parameters.get(0))/Integer.parseInt(this.parameters.get(2));
- break;
- default:
- throw new IllegalArgumentException("Comando desconocido: ");
- }
- solvedUnkowns.put(result, resultUnknown);
- }else if(this.parameters.get(0).matches("[A-Z]+")){
- int resultUnknown=0;
- switch(this.parameters.get(1)) {
- case "+":
- resultUnknown = Integer.parseInt(result)-Integer.parseInt(this.parameters.get(2));
- break;
- case "-":
- resultUnknown = Integer.parseInt(this.parameters.get(2))+Integer.parseInt(result);
- break;
- case "*":
- resultUnknown = Integer.parseInt(result)/Integer.parseInt(this.parameters.get(2));
- break;
- case "/":
- resultUnknown = Integer.parseInt(result)*Integer.parseInt(this.parameters.get(2));
- break;
- default:
- throw new IllegalArgumentException("Comando desconocido: ");
- }
- solvedUnkowns.put(this.parameters.get(0), resultUnknown);
- }else if(this.parameters.get(2).matches("[A-Z]+")){
- int resultUnknown=0;
- switch(this.parameters.get(1)) {
- case "+":
- resultUnknown = Integer.parseInt(result)-Integer.parseInt(this.parameters.get(0));
- break;
- case "-":
- resultUnknown = Integer.parseInt(this.parameters.get(0))-Integer.parseInt(result);
- break;
- case "*":
- resultUnknown = Integer.parseInt(result)/Integer.parseInt(this.parameters.get(0));
- break;
- case "/":
- resultUnknown = Integer.parseInt(this.parameters.get(0))/Integer.parseInt(result);
- break;
- default:
- throw new IllegalArgumentException("Comando desconocido: ");
- }
- solvedUnkowns.put(this.parameters.get(2), resultUnknown);
- }
- }
- }
- public static String[][] solve(String[][] board) {
- HashMap<String, Integer> solvedUnkowns = new HashMap<String, Integer>();
- LinkedList<Operation> operations = new LinkedList<CrossMath.Operation>();
- for (int row = 0; row < board.length; row += 2) {
- ArrayList<String> parameters = new ArrayList<String>();
- for (int col = 0; col < board[row].length; col++) {
- if ("=".equals(board[row][col])) {
- operations.add(new Operation(parameters, board[row][col+1]));
- parameters = new ArrayList<String>();
- } else {
- parameters.add(board[row][col]);
- }
- }
- }
- for (int col = 0; col < board[0].length; col += 2) {
- ArrayList<String> parameters = new ArrayList<String>();
- for (int row = 0; row < board.length; row++) {
- if ("=".equals(board[row][col])) {
- operations.add(new Operation(parameters, board[row+1][col]));
- parameters = new ArrayList<String>();
- } else {
- parameters.add(board[row][col]);
- }
- }
- }
- int cont = 0;
- while (0 < operations.size()) {
- Operation op = operations.pollFirst();
- switch (op.unknownAmmount(solvedUnkowns)) {
- case 0:
- cont = 0;
- break;
- case 1:
- op.calculateUnkown(solvedUnkowns);
- cont = 0;
- break;
- default:
- operations.addLast(op);
- cont++;
- break;
- }
- if (operations.size() <= cont) {
- String[][] res = new String[5][5];
- for(int i = 0; i < board.length; i++) {
- for(int k = 0; k < board[i].length; k++) {
- if(board[i][k].matches("[A-Z]")) {
- res[i][k] = String.valueOf(solvedUnkowns.get(board[i][k]));
- }else {
- res[i][k] = board[i][k];
- }
- }
- }
- return res;
- }
- }
- return null;
- }
- }
import static org.junit.jupiter.api.Assertions.assertArrayEquals; import java.util.Arrays; import java.util.Random; import org.junit.jupiter.api.Test; class SolutionTest { @Test void TestRandomA() { for(int z = 0; z < 100; z++) { String[][] board = generatePlusMinusMultiDiv(); String[][] end = generatePlusMinusMultiDiv(); for(int i = 0; i < end.length; i++) { end[i] = board[i].clone(); } for(int i = 0; i < board.length; i++) { for(int k = 0; k < board[i].length; k++) { end[i][k] = board[i][k]; } } board = incognitaCreator(board); System.out.println(Arrays.deepToString(board)); System.out.println(Arrays.deepToString(end)); assertArrayEquals(end, CrossMath.solve(board)); } } public static String[][] generatePlusMinusMultiDiv() { Random r = new Random(); String[][] moss = new String[5][5]; if(r.nextInt(2) == 1) { int mult = r.nextInt(5)+1; int base = r.nextInt(5)+5; int num = base*mult; if(base > mult) { moss[1][2] = "+"; moss[2][1] = "+"; }else { moss[1][2] = "-"; moss[2][1] = "-"; } moss[0][0] = String.valueOf(base); moss[0][1] = "+"; moss[0][2] = String.valueOf(num-base); moss[0][3] = "="; moss[0][4] = String.valueOf(num); moss[1][0] = "*"; moss[1][1] = " "; moss[1][3] = " "; moss[1][4] = "/"; moss[2][0] = String.valueOf(mult); moss[2][2] = String.valueOf(Math.abs(base-mult)); moss[2][3] = "="; moss[2][4] = String.valueOf(base); moss[3][0] = "="; moss[3][1] = " "; moss[3][2] = "="; moss[3][3] = " "; moss[3][4] = "="; moss[4][0] = String.valueOf(num); moss[4][1] = "-"; moss[4][2] = String.valueOf(num-mult); moss[4][3] = "="; moss[4][4] = String.valueOf(mult); }else { int mult = r.nextInt(9)+1; int base = r.nextInt(9)+1; int num = base*mult; if(base < mult) { moss[1][2] = "-"; moss[2][1] = "+"; }else { moss[1][2] = "+"; moss[2][1] = "-"; } moss[0][0] = String.valueOf(num); moss[0][1] = "-"; moss[0][2] = String.valueOf(num-base); moss[0][3] = "="; moss[0][4] = String.valueOf(base); moss[1][0] = "/"; moss[1][1] = " "; moss[1][3] = " "; moss[1][4] = "*"; moss[2][0] = String.valueOf(base); moss[2][2] = String.valueOf(Math.abs(base-mult)); moss[2][3] = "="; moss[2][4] = String.valueOf(mult); moss[3][0] = "="; moss[3][1] = " "; moss[3][2] = "="; moss[3][3] = " "; moss[3][4] = "="; moss[4][0] = String.valueOf(mult); moss[4][1] = "+"; moss[4][2] = String.valueOf(num-mult); moss[4][3] = "="; moss[4][4] = String.valueOf(num); } return moss; } public static String[][] incognitaCreator(String[][] moss) { String[] arr = {"A","B","C"}; Random r = new Random(); for(String a : arr) { moss[r.nextInt(3)*2][r.nextInt(3)*2] = a; } return moss; } }
import org.junit.jupiter.api.Test;import static org.junit.jupiter.api.Assertions.assertEquals;- import static org.junit.jupiter.api.Assertions.assertArrayEquals;
- import java.util.Arrays;
- import java.util.Random;
// TODO: Replace examples and use TDD by writing your own tests- import org.junit.jupiter.api.Test;
- class SolutionTest {
- @Test
void testSomething() {// assertEquals("expected", "actual");}- void TestRandomA() {
- for(int z = 0; z < 100; z++) {
- String[][] board = generatePlusMinusMultiDiv();
- String[][] end = generatePlusMinusMultiDiv();
- for(int i = 0; i < end.length; i++) {
- end[i] = board[i].clone();
- }
- for(int i = 0; i < board.length; i++) {
- for(int k = 0; k < board[i].length; k++) {
- end[i][k] = board[i][k];
- }
- }
- board = incognitaCreator(board);
- System.out.println(Arrays.deepToString(board));
- System.out.println(Arrays.deepToString(end));
- assertArrayEquals(end, CrossMath.solve(board));
- }
- }
- public static String[][] generatePlusMinusMultiDiv() {
- Random r = new Random();
- String[][] moss = new String[5][5];
- if(r.nextInt(2) == 1) {
- int mult = r.nextInt(5)+1;
- int base = r.nextInt(5)+5;
- int num = base*mult;
- if(base > mult) {
- moss[1][2] = "+";
- moss[2][1] = "+";
- }else {
- moss[1][2] = "-";
- moss[2][1] = "-";
- }
- moss[0][0] = String.valueOf(base);
- moss[0][1] = "+";
- moss[0][2] = String.valueOf(num-base);
- moss[0][3] = "=";
- moss[0][4] = String.valueOf(num);
- moss[1][0] = "*";
- moss[1][1] = " ";
- moss[1][3] = " ";
- moss[1][4] = "/";
- moss[2][0] = String.valueOf(mult);
- moss[2][2] = String.valueOf(Math.abs(base-mult));
- moss[2][3] = "=";
- moss[2][4] = String.valueOf(base);
- moss[3][0] = "=";
- moss[3][1] = " ";
- moss[3][2] = "=";
- moss[3][3] = " ";
- moss[3][4] = "=";
- moss[4][0] = String.valueOf(num);
- moss[4][1] = "-";
- moss[4][2] = String.valueOf(num-mult);
- moss[4][3] = "=";
- moss[4][4] = String.valueOf(mult);
- }else {
- int mult = r.nextInt(9)+1;
- int base = r.nextInt(9)+1;
- int num = base*mult;
- if(base < mult) {
- moss[1][2] = "-";
- moss[2][1] = "+";
- }else {
- moss[1][2] = "+";
- moss[2][1] = "-";
- }
- moss[0][0] = String.valueOf(num);
- moss[0][1] = "-";
- moss[0][2] = String.valueOf(num-base);
- moss[0][3] = "=";
- moss[0][4] = String.valueOf(base);
- moss[1][0] = "/";
- moss[1][1] = " ";
- moss[1][3] = " ";
- moss[1][4] = "*";
- moss[2][0] = String.valueOf(base);
- moss[2][2] = String.valueOf(Math.abs(base-mult));
- moss[2][3] = "=";
- moss[2][4] = String.valueOf(mult);
- moss[3][0] = "=";
- moss[3][1] = " ";
- moss[3][2] = "=";
- moss[3][3] = " ";
- moss[3][4] = "=";
- moss[4][0] = String.valueOf(mult);
- moss[4][1] = "+";
- moss[4][2] = String.valueOf(num-mult);
- moss[4][3] = "=";
- moss[4][4] = String.valueOf(num);
- }
- return moss;
- }
- public static String[][] incognitaCreator(String[][] moss) {
- String[] arr = {"A","B","C"};
- Random r = new Random();
- for(String a : arr) {
- moss[r.nextInt(3)*2][r.nextInt(3)*2] = a;
- }
- return moss;
- }
- }
A crossword (also called cruciverbalist) is a puzzle in which given a clue, white spaces and black spaces you need to fill the white spaces with letters. Usually, words fill a letter of another word, giving you another clue.
This type of crossword works moreless like that.
Given some mathematical expresions you need to find out the value of the incognita with the values you know.
Some expresions have more than one incognita, making you figure one of the unknown values via another expresion that can be resolved.
You will be given a bidimensional array of Strings which will have the following format:
String[][] cross = {
{"1","+","A","=","6"},
{"+"," ","-"," ","+"},
{"B","-","3","=","4"},
{"="," ","="," ","="},
{"8","+","C","=","D"}};
Which will return:
String[][] cross = {
{"1","+","5","=","6"},
{"+"," ","-"," ","+"},
{"7","-","3","=","4"},
{"="," ","="," ","="},
{"8","+","2","=","10"}};
To make it simple, you will follow some rules:
- All numbers will be positive Integers.
- The results of the operations will be positive Integers.
- The array will always have the same number of lines and columns.
- The incognita could be in any position of the operation.
- The function will always receive at least a correctly filled 5x5 array, not a null, an empty or an incorrect array.
- The size of the array could be bigger than 5x5, but always odd.
- The jerachy will be from left to right and from up to down. Sums and substractions at left will be before mutiplications and divisions at right.
- The corners of the array will never be all incognitas.
class Crossword{
}
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
// TODO: Replace examples and use TDD by writing your own tests
class SolutionTest {
@Test
void testSomething() {
// assertEquals("expected", "actual");
}
}