From 988d211db67c6591b3fb12ca82dd531d35f25c5c Mon Sep 17 00:00:00 2001 From: gaven Date: Fri, 26 Sep 2025 16:44:43 +0000 Subject: [PATCH] Upload files to "WitchGame" --- WitchGame/EnemyAttack.java | 78 ++++ WitchGame/Equipment.java | 87 ++++ WitchGame/EquipmentType.java | 15 + WitchGame/Item.java | 53 +++ WitchGame/MapSections.java | 784 +++++++++++++++++++++++++++++++++++ 5 files changed, 1017 insertions(+) create mode 100644 WitchGame/EnemyAttack.java create mode 100644 WitchGame/Equipment.java create mode 100644 WitchGame/EquipmentType.java create mode 100644 WitchGame/Item.java create mode 100644 WitchGame/MapSections.java diff --git a/WitchGame/EnemyAttack.java b/WitchGame/EnemyAttack.java new file mode 100644 index 0000000..bb43d90 --- /dev/null +++ b/WitchGame/EnemyAttack.java @@ -0,0 +1,78 @@ +package witchGame; + +import java.util.ArrayList; +import java.util.Random; + +@SuppressWarnings("unused") +public class EnemyAttack { + Random rand = new Random(); + private String name; + private int toHit = 0; + private int die = 1; + private int sides = 1; + private int damage = 0; + private int damageType = 0; + private int numberHits = 1; + private int saveThrow = 1; // Str 1 | Dex 2 | Con 3 | Int 4 | Wis 5 | Chr 6 + private Condition condition = null; + + public EnemyAttack(int numberHits, String name, int toHit, int die, int sides, int damage, int damageType) { + this.name = name; +// this.speed = speed; + this.toHit = toHit; + this.die = die; + this.sides = sides; + this.damageType = damageType; + this.numberHits = numberHits; + } + public EnemyAttack(int numberHits, String name, int toHit, int die, int sides, int damage, int damageType, int saveThrow) { + this.name = name; +// this.speed = speed; + this.toHit = toHit; + this.die = die; + this.sides = sides; + this.damageType = damageType; + this.numberHits = numberHits; + this.saveThrow = saveThrow; + } + //TODO: pass conditions and consider advantage disadvantage + public int attack(ArrayList conditions) { + int damageTotal = 0; + for (int a = 0; a < numberHits; a++) { + int rollToHit = rand.nextInt(21) + toHit; + + int advantageOrDisadvantage = 0; + for (Condition condition : conditions) { + switch (condition.getConditionType()) { + + default: + + } + } +// for (Condition condition : witch.playerConditions) { +// switch (condition.getConditionType()) { +// default: +// +// } +// } + + + if (witch.playerAC < rollToHit) { + damageTotal += witch.dice(die, sides) + damage; + System.out.println(" " + name + ": " + damageTotal + " " + witch.damageTypes[damageType] + " damage!"); + } else { + System.out.println(" " + name + ": Missed!"); + } + } + return damageTotal; + } + + public String toString() { + return (name + "\n+" + toHit + " to Hit\n" + die + "d" + sides + " + " + damage + " " + damageType + " damage"); +// if (condition != null) { +// +// } + } + + // damageTypes = {"acid", "bludgeoning", "cold", "fire", "force", "lightning", "necrotic", "piercing", "poison", "psychic", "radiant", "slashing", "thunder"}; +} diff --git a/WitchGame/Equipment.java b/WitchGame/Equipment.java new file mode 100644 index 0000000..e5eed33 --- /dev/null +++ b/WitchGame/Equipment.java @@ -0,0 +1,87 @@ +package witchGame; + +import java.util.ArrayList; +import java.util.List; + +public class Equipment extends Item { + +// private String name; +// private int cost; + private ArrayList constantEffects; + private ArrayList abilityEffects; +// private TargetType abilityTarget; +// private int maxAbilityUses; +// private int abilityUses; + + @Override + public String toString() { + String toString = "Equipment: " + name + "\nEquipslot: " + equipSlot + "\n"; + if (constantEffects.size() > 0) { + toString += "Wearer has: \n"; + for (Condition condition : constantEffects) { + toString += condition.toString(); + } + } + if (abilityEffects.size() > 0) { + toString += "Ability:\n"; + switch (abilityTarget) { + case Self: toString += "Apply to Self\n"; break; + case Enemy: toString += "Apply to Target Enemy\n"; break; + case AllEnemies: toString += "Apply to All Enemies\n"; break; + default: break; + } + for (Condition condition : abilityEffects) { + toString += condition.toString(); + } + } + + return toString; + } + + + public Equipment(String name, EquipmentType equipSlot, int cost, ArrayList constantEffects, + ArrayList abilityEffects, TargetType abilityTarget, int maxAbilityUses) { + super(); + this.name = name; + this.equipSlot = equipSlot; + this.cost = cost; + this.constantEffects = constantEffects; + this.abilityEffects = abilityEffects; + this.abilityTarget = abilityTarget; + this.maxAbilityUses = maxAbilityUses; + this.abilityUses = this.maxAbilityUses; + } + + public Equipment(String name, EquipmentType equipSlot, int cost, ArrayList constantEffects) { + super(); + this.name = name; + this.equipSlot = equipSlot; + this.cost = cost; + this.constantEffects = constantEffects; + this.abilityEffects = null; + this.abilityTarget = null; + this.maxAbilityUses = 0; + this.abilityUses = this.maxAbilityUses; + } + + public Equipment(String name, EquipmentType equipSlot, int cost, ArrayList abilityEffects, + TargetType abilityTarget, int maxAbilityUses) { + super(); + this.name = name; + this.equipSlot = equipSlot; + this.cost = cost; + this.constantEffects = null; + this.abilityEffects = abilityEffects; + this.abilityTarget = abilityTarget; + this.maxAbilityUses = maxAbilityUses; + this.abilityUses = this.maxAbilityUses; + } + + + public static ArrayList equipmentList = new ArrayList(); + + static { + equipmentList.add(new Equipment("Breastplate", EquipmentType.Chest, 750, new ArrayList(List.of(new Condition(ConditionType.ModifierOnAC, 999, 6), new Condition(ConditionType.DisadvantageOnAttacks, 999))))); // + } + +} \ No newline at end of file diff --git a/WitchGame/EquipmentType.java b/WitchGame/EquipmentType.java new file mode 100644 index 0000000..aa878ab --- /dev/null +++ b/WitchGame/EquipmentType.java @@ -0,0 +1,15 @@ +package witchGame; + +public enum EquipmentType { + + Null, + + Head, + Chest, + OneArm, + TwoArms, + Legs, + Trinket, + Consumable, + +} diff --git a/WitchGame/Item.java b/WitchGame/Item.java new file mode 100644 index 0000000..4a3e644 --- /dev/null +++ b/WitchGame/Item.java @@ -0,0 +1,53 @@ +package witchGame; + +public abstract class Item implements Cloneable { + + protected String name; + protected EquipmentType equipSlot; + protected int cost; + protected TargetType abilityTarget; + protected int abilityUses; + protected int maxAbilityUses; + + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public TargetType getAbilityTarget() { + return abilityTarget; + } + + public int getAbilityUses() { + return abilityUses; + } + + public void setAbilityUses(int abilityUses) { + this.abilityUses = abilityUses; + if (this.abilityUses > maxAbilityUses) { + this.abilityUses = maxAbilityUses; + } + } + + public int getCost() { + return cost; + } + + public void setCost(int cost) { + this.cost = cost; + } + + public EquipmentType getEquipSlot() { + return equipSlot; + } + + @Override + public String toString() { + return "Item: " + name + "\n"; + } + +} diff --git a/WitchGame/MapSections.java b/WitchGame/MapSections.java new file mode 100644 index 0000000..f5b0bd7 --- /dev/null +++ b/WitchGame/MapSections.java @@ -0,0 +1,784 @@ +package witchGame; + +import java.awt.color.*; +import java.awt.geom.Path2D; +import java.awt.image.BufferedImage; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.DoubleStream; +import java.awt.Graphics; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Graphics2D; +import javax.swing.JPanel; + +//@SuppressWarnings("unused") +public class MapSections extends JPanel { + private static final long serialVersionUID = 1L; + + private int[][] regions; + private int[][] points; + private Color color; + private int e = 20; + private int offset = 25; + private Color[] regionColors = { Color.WHITE, Color.CYAN, Color.YELLOW, new Color(0, 64, 2) /* Forest Green */, + new Color(148, 200, 132) /* Mid Green */, new Color(107, 205, 0), + new Color(150, 150, 150) /* Darker Gray */, new Color(53, 74, 33) /* Aquamarine */, Color.DARK_GRAY, + Color.BLUE, Color.ORANGE }; + Color myWhite = new Color(255, 255, 255); + private boolean debug = !true; + +// final static String[] biomes = {"arctic", "coastal", "desert", "forest", "grassland", "hills", "mountains", "swampland", "underdark", "underwater", "urban"}; + + @Override + protected void paintComponent(Graphics g) { + super.paintComponent(g); + Graphics2D g2 = (Graphics2D) g; + + boolean[][] adjacent = new boolean[witchRunner.regions.length][witchRunner.regions.length]; + ArrayList adj = new ArrayList<>(); + for (int r = 0; r < regions.length; r++) { + adj.clear(); + for (int x = 0; x < witch.map_.length; x++) { + for (int y = 0; y < witch.map_[0].length; y++) { + if (witch.map_[x][y] == r) { + if (x != 0) { + if (y != witch.map_[0].length - 1) + adj.add(witch.map_[x - 1][y + 1]); + adj.add(witch.map_[x - 1][y]); + if (y != 0) + adj.add(witch.map_[x - 1][y - 1]); + } + if (x != witch.map_.length - 1) { + if (y != witch.map_[0].length - 1) + adj.add(witch.map_[x + 1][y + 1]); + adj.add(witch.map_[x + 1][y]); + if (y != 0) + adj.add(witch.map_[x + 1][y - 1]); + } + if (y != witch.map_[0].length - 1) + adj.add(witch.map_[x][y + 1]); + if (y != 0) + adj.add(witch.map_[x][y - 1]); + } + } + } + for (int i = 0; i < adjacent.length; i++) { +// adj.remove(i); // This removes one of each number from the adj array, meaning there has to be at least 2 places close to each region + if (adj.contains(i) && i != r) { + adjacent[r][i] = true; + } else { + adjacent[r][i] = false; + } + } + } +// for (int x = 0; x < adjacent.length; x++) { +// System.out.print("\n" + x + " is adjacent to: "); +// for (int y = 0; y < adjacent[x].length; y++) { +// if (adjacent[x][y]) { +// System.out.print(y + ", "); +// } +// } +// } +// System.out.println(); + + + +// g2.setColor(Color.BLUE); // TODO:? +// g2.setStroke(new BasicStroke(10)); + + Path2D linesBetween = new Path2D.Double(); + +// int[][] adjacentLines = new int[99999999][2]; + int num = 0; + for (int i = 0; i < adjacent.length; i++) { + for (int j = i + 1; j < adjacent.length; j++) { + if (adjacent[i][j]) { + linesBetween.moveTo(offset + regions[i][1] * e, offset + regions[i][0] * e); + linesBetween.lineTo(offset + regions[j][1] * e, offset + regions[j][0] * e); +// adjacentLines[num][0] = i; +// adjacentLines[num++][1] = j; + } + } + } + + g2.draw(linesBetween); + + g2.setColor(Color.GREEN); + g2.setStroke(new BasicStroke(4)); + + num = 0; + double[][] possibleCircumcenters = new double[604800][6]; + for (int a = 0; a < regions.length; a++) { + for (int b = a + 1; b < regions.length; b++) { + for (int c = b + 1; c < regions.length; c++) { +// System.arraycopy(array1, 0, array1and2, 0, array1.length); +// System.arraycopy(array2, 0, array1and2, array1.length, array2.length); +// System.out.println(a + "" + b + "" + c); + double[] x = Arrays.stream(regions[a]).asDoubleStream().toArray(); + double[] y = Arrays.stream(regions[b]).asDoubleStream().toArray(); + double[] z = Arrays.stream(regions[c]).asDoubleStream().toArray(); + double[] circ = findCircumCenter(x, y, z); + System.arraycopy(circ, 0, possibleCircumcenters[num], 0, circ.length); + System.arraycopy(new double[] { a, b, c }, 0, possibleCircumcenters[num++], circ.length, 3); +// System.out.print("\t"); +// for (int i : possibleCircumcenters[num-1]) +// System.out.print(i + " "); +// System.out.println("\n\n"); +// possibleCircumcenters[num] = new int[] {findCircumCenter(regions[a], regions[b], regions[c])}; + } + } + } + ArrayList realCircumcenters = new ArrayList(); + for (double[] x : possibleCircumcenters) { +// if (withinBorders(x)) { + if (adjacent[(int) x[2]][(int) x[3]] && adjacent[(int) x[2]][(int) x[4]] && adjacent[(int) x[3]][(int) x[4]]) { + int closest = 0; + for (int d = 0; d < regions.length; d++) { + int[] r = regions[d]; + if (dist(new double[] {regions[closest][0], regions[closest][1]}, x) > dist(new double[] {r[0], r[1]}, x)) { + closest = d; + } + } + if ((int) x[2] == closest || (int) x[3] == closest || (int) x[4] == closest) { + System.out.println("Circumcenter @: " + x[2] + " " + x[3] + " " + x[4]); + realCircumcenters.add(x); + } + } +// } + } + + Path2D circumcenterLines = new Path2D.Double(); + Path2D borderCircumcenterLines = new Path2D.Double(); + + g2.setColor(Color.RED); + g2.setStroke(new BasicStroke(4)); + + for (int a = 0; a < realCircumcenters.size(); a++) { + for (int b = a + 1; b < realCircumcenters.size(); b++) { + int count = 0; + for (int i = 2; i < 5; i++) { +// if (connections.get(a)[i] == connections.get(b)[2] || connections.get(a)[i] == connections.get(b)[3] || connections.get(a)[i] == connections.get(b)[4]) { + if (realCircumcenters.get(a)[i] == realCircumcenters.get(b)[2] + || realCircumcenters.get(a)[i] == realCircumcenters.get(b)[3] + || realCircumcenters.get(a)[i] == realCircumcenters.get(b)[4]) + count++; + } + if (count > 1) { + circumcenterLines.moveTo(offset + realCircumcenters.get(a)[1] * e, + offset + realCircumcenters.get(a)[0] * e); + circumcenterLines.lineTo(offset + realCircumcenters.get(b)[1] * e, + offset + realCircumcenters.get(b)[0] * e); + realCircumcenters.get(a)[5]++; + realCircumcenters.get(b)[5]++; + } + } + } + + int[][] border = { + {0, 1, 0}, + {1, 0, 0}, + {0, 1, witch.map[0].length}, + {1, 0, witch.map.length} + }; + + for (int a = 0; a < regions.length; a++) { + for (int b = a + 1; b < regions.length; b++) { + if (adjacent[a][b]) { + int[] count = {0,0,0}; + num = 0; + for (int i = 0; i < realCircumcenters.size(); i++) { + double[] circ = realCircumcenters.get(i); + if ((circ[2] == a || circ[3] == a || circ[4] == a) && (circ[2] == b || circ[3] == b || circ[4] == b)) { + count[num++] = i; + } + } +// System.out.println("A:" + a + "B:" + b); + if (num == 0) { // If 0 indexes were used in the count check; AKA if there are no circumcenters associated with these adjacent regions + + double[] aDouble = Arrays.stream(regions[a]).asDoubleStream().toArray(); + double[] bDouble = Arrays.stream(regions[b]).asDoubleStream().toArray(); + + + double[] line = lineFromPoints(aDouble, bDouble); + double[] perp = perpendicularBisectorFromLine(aDouble, bDouble, line); + + double[][] borderPoints = { + lineLineIntersection(border[0][0], border[0][1], border[0][2], perp[0], perp[1], perp[2]), + lineLineIntersection(border[1][0], border[1][1], border[1][2], perp[0], perp[1], perp[2]), + lineLineIntersection(border[2][0], border[2][1], border[2][2], perp[0], perp[1], perp[2]), + lineLineIntersection(border[3][0], border[3][1], border[3][2], perp[0], perp[1], perp[2]) + }; + +// for (int[] bor : borderPoints) { // Remove the 2 border points that are outside the borders +// if (bor[0] < 0 || bor[0] > witch.map.length || bor[1] < 0 || bor[1] > witch.map[0].length) { +// bor = new int[] {Integer.MAX_VALUE, Integer.MAX_VALUE}; +// } +// } + int[] closest = {0,0}; // Initialize variable for the 2 closest points + double[] dMin = {Integer.MAX_VALUE, Integer.MAX_VALUE}; // Initialize variable for the distances of the 2 closest points +// int x1 = realCircumcenters.get(count[0])[0]; +// int y1 = realCircumcenters.get(count[0])[1]; + double x1 = regions[a][0]; + double y1 = regions[a][1]; + for (int i = 0; i < borderPoints.length; i++) { + double x2 = borderPoints[i][0]; + double y2 = borderPoints[i][1]; + double dist = Math.sqrt(Math.pow((x1-x2), 2) + Math.pow((y1-y2), 2)); + dist = dist(aDouble, bDouble); +// double d = Math.sqrt(Math.pow(regions[r][0] - x, 2) + Math.pow(regions[r][1] - y, 2)); + if (withinBorders(new double[] {x2, y2})) { + if (dist <= dMin[0]) { + closest[1] = closest[0]; + dMin[1] = dMin[0]; + closest[0] = i; + dMin[0] = dist; + } else if (dist <= dMin[1]) { + closest[1] = i; + dMin[1] = dist; + } + } + } + + realCircumcenters.add(new double[] {borderPoints[closest[0]][0], borderPoints[closest[0]][1], a, b, -1}); + realCircumcenters.add(new double[] {borderPoints[closest[1]][0], borderPoints[closest[1]][1], a, b, -1}); + + + borderCircumcenterLines.moveTo(offset + borderPoints[closest[0]][1] * e, // First point on the line + offset + borderPoints[closest[0]][0] * e); + + borderCircumcenterLines.lineTo(offset + borderPoints[closest[1]][1] * e, // Second point on the line + offset + borderPoints[closest[1]][0] * e); + +// realCircumcenters.get(count[0])[5]++; // Unused for now; Indicator for whether the circumcenters are connected to 3 other points + + } else if (num == 1) { // If 1 index were used in the count check; AKA if there is only one circumcenter associated with these adjacent regions +// System.out.println("NOTE"); + // Make a perpendicular bisector + double[] cir = realCircumcenters.get(count[0]); // Finds the third region and calls it c. We now have 3 regions a, b, c that are all adjacent and have a circumcenter which is called cir. a and b do not have another circumcenter with each other. + int c = -1; + for (int z = 2; z < 5; z++) { + if (cir[z] != a && cir[z] != b) { + c = (int) cir[z]; + } + } + + // Seperate 2 border points from 1 border points and do each seperately + + num = 0; + int[] count2 = {0,0,0}; + for (int rC = 0; rC < realCircumcenters.size(); rC++) { // Find circumcenters next to this one + double[] circ = realCircumcenters.get(rC); + if ((circ[2] == c || circ[3] == c || circ[4] == c) && ((circ[2] == a || circ[3] == a || circ[4] == a) ^ (circ[2] == b || circ[3] == b || circ[4] == b))) { +// System.out.println("Sections: " + a + " " + b + " " + c); +// System.out.println("Circumcenter: " + circ[0] + ", " + circ[1] + ", " + circ[2] + ", " + circ[3] + ", " + circ[4]); +// outVectors[num] = new double[] {circ[0]-x1, circ[1]-y1}; + if (circ[4] != -1) + count2[num++] = rC; + } + } + + double[] x = Arrays.stream(regions[a]).asDoubleStream().toArray(); + double[] y = Arrays.stream(regions[b]).asDoubleStream().toArray(); + double[] z = Arrays.stream(regions[c]).asDoubleStream().toArray(); + + + + double x1 = cir[0]; // X-value of the circumcenter + double y1 = cir[1]; // Y-value of the circumcenter + + + + if (num == 2) { // The circumcenter in question is connected to 2 other circumcenters: realCircumcenters.get(count2[0]) and realCircumcenters.get(count2[1]) + double[] line = lineFromPoints(x, y); // Find the equation of a line between a and b + double[] perp = perpendicularBisectorFromLine(x, y, line); // Find the perpendicular bisector of a and b + + double[][] borderPoints = { // Find the intersection points of each of the borders with the perpendicular bisector of a and b + lineLineIntersection(border[0][0], border[0][1], border[0][2], perp[0], perp[1], perp[2]), + lineLineIntersection(border[1][0], border[1][1], border[1][2], perp[0], perp[1], perp[2]), + lineLineIntersection(border[2][0], border[2][1], border[2][2], perp[0], perp[1], perp[2]), + lineLineIntersection(border[3][0], border[3][1], border[3][2], perp[0], perp[1], perp[2]) + }; + double[][] adjacentCircumcenters = new double[2][]; + num = 0; + for (double[] circ : realCircumcenters) { + int countRegions = 0; + for (int i = 2; i <= 4; i++) { +// System.out.println(i); +// System.out.println("i = " + i + "\n " + circ[i] + "\na - " + a + "\tb - " + b + "\tc - " + c); + + if (circ[i] == a || circ[i] == b || circ[i] == c) { +// System.out.println("i = " + i + "\n\ta - " + circ[i]); +// System.out.println(circ[i] == a); +// System.out.println(circ[i] == b); +// System.out.println(circ[i] == c); + countRegions++; + + } + } + if (countRegions == 2 && circ[4] != -1) { +// System.out.println("Found Adjacent Circ: " + circ[0] + " " + circ[1] + " " + circ[2] + " " + circ[3] + " " + circ[4]); + adjacentCircumcenters[num++] = circ; + } + } + + double[][] unitVectors = {unitVector(adjacentCircumcenters[0], cir), unitVector(adjacentCircumcenters[1], cir)}; + double[] unitVectorsAdded = {unitVectors[0][0] + unitVectors[1][0], unitVectors[0][1] + unitVectors[1][1]}; +// double[] outVectorsMagnitude = {Math.sqrt(Math.pow((outVectors[0][0]), 2) + Math.pow((outVectors[0][1]), 2)), Math.sqrt(Math.pow((outVectors[1][0]), 2) + Math.pow((outVectors[1][1]), 2))}; // TODO: change to use dist command + +// outVectors[0] = new double[] {outVectors[0][0]/outVectorsMagnitude[0], outVectors[0][1]/outVectorsMagnitude[0]}; +// outVectors[1] = new double[] {outVectors[1][0]/outVectorsMagnitude[1], outVectors[1][1]/outVectorsMagnitude[1]}; +// double[] outVector = new double[] {outVectors[0][0] + outVectors[1][0], outVectors[0][1] + outVectors[1][1]}; + + int closest = -1; // Initialize a variable for the closest intersection point + double dMin = Integer.MAX_VALUE; // Initialize a variable for the distance to the closest intersection point + + for (int bor = 0; bor < borderPoints.length; bor++) { + double x2 = borderPoints[bor][0]; + double y2 = borderPoints[bor][1]; + double dist = dist(cir, borderPoints[bor]); +// double d = Math.sqrt(Math.pow(regions[r][0] - x, 2) + Math.pow(regions[r][1] - y, 2)); + + double[] distVector = {x2-x1, y2-y1}; + + if (distVector[0] * unitVectorsAdded[0] + distVector[1] * unitVectorsAdded[1] > 0) { // Determine the direction of the vector projection between 2 lines: c to circumcenter and intersection point to circumcenter + // The line is in the same direction as the opposite vertex, which means reject this border point: it is in the wrong direction + } else if (dist <= dMin) { // If the distance of this point is closer, replace the old point and distance + closest = bor; + dMin = dist; + } + + } + if (closest >= 0) { + if (withinBorders(new double[] {borderPoints[closest][0], borderPoints[closest][1]})) { + realCircumcenters.add(new double[] {borderPoints[closest][0], borderPoints[closest][1], a, b, -1}); + + borderCircumcenterLines.moveTo(offset + realCircumcenters.get(count[0])[1] * e, // First point on the line + offset + realCircumcenters.get(count[0])[0] * e); + borderCircumcenterLines.lineTo(offset + borderPoints[closest][1] * e, // Second point on the line + offset + borderPoints[closest][0] * e); + realCircumcenters.get(count[0])[5]++; // Currently unused + } + } + } else if (num == 1) { // The circumcenter in question is connected to only 1 circumcenter: realCircumcenters.get(count2[0]) + //TODO: + + double[][] unitVectors = new double[3][2]; + + double[][][] allBorderPoints = new double[2][4][]; + double[][][] realBorderPoints = new double[2][4][]; + + unitVectors[2] = unitVector(cir, realCircumcenters.get(count2[0])); + + double[][] lineComboRegions = new double[][] { + {a, b}, + {a, c}, + }; + + double[][][] lineCombos = new double[][][] { + {x, y}, + {x, z}, + }; + + if (realCircumcenters.get(count2[0])[2] == a || realCircumcenters.get(count2[0])[3] == a || realCircumcenters.get(count2[0])[4] == a) { + lineCombos[1][0] = y; + lineComboRegions[1][0] = b; + } + + + for (int iterate = 0; iterate <= 1; iterate++) { + + int closest = 0; + double dMin = Integer.MAX_VALUE; + + double[] line = lineFromPoints(lineCombos[iterate][0], lineCombos[iterate][1]); // Find the equation of a line between a and b + double[] perp = perpendicularBisectorFromLine(lineCombos[iterate][0], lineCombos[iterate][1], line); // Find the perpendicular bisector of a and b + + allBorderPoints[iterate] = new double[][] { // Find the intersection points of each of the borders with the perpendicular bisector of a and b + lineLineIntersection(border[0][0], border[0][1], border[0][2], perp[0], perp[1], perp[2]), + lineLineIntersection(border[1][0], border[1][1], border[1][2], perp[0], perp[1], perp[2]), + lineLineIntersection(border[2][0], border[2][1], border[2][2], perp[0], perp[1], perp[2]), + lineLineIntersection(border[3][0], border[3][1], border[3][2], perp[0], perp[1], perp[2]) + }; + +// double distMin = Integer.MAX_VALUE; + for (double[] borderPointsIteration : allBorderPoints[iterate]) { +// System.out.print(allBorderPoints[i][0]); +// double[] bP = borderPoints[iterate][i]; + if (!withinBorders(borderPointsIteration)) { +// allBorderPoints[iterate][i] = new double[] {Integer.MAX_VALUE, Integer.MAX_VALUE}; + } else { +// System.out.println("Enter- \n" + "Circumcenter: " + cir[0] + "," + cir[1] + "\nIterate: " + iterate + "; Border: " + borderPointsIteration[0] + "," + borderPointsIteration[1]); + if (dist(cir, borderPointsIteration) < dMin) { + realBorderPoints[iterate][1] = realBorderPoints[iterate][0]; + realBorderPoints[iterate][0] = borderPointsIteration; + dMin = dist(cir, borderPointsIteration); +// System.out.println("True:" + dMin); + + } else { + realBorderPoints[iterate][1] = borderPointsIteration; + } + } + } + unitVectors[iterate] = unitVector(cir, realBorderPoints[iterate][0]); +// System.out.println(dist(cir, realBorderPoints[iterate][0])); + if (dist(cir, realBorderPoints[iterate][0]) == 0) { + unitVectors[iterate] = new double[] {0,0}; +// System.out.println("- 00"); + } + } + + double largestSmallAngle = Integer.MIN_VALUE; + int smallestAngleValue = -1; + + // unitVectors are vectors to the 2 closest in-bounds borders and the circumcenter + + for (int iterate = 0; iterate < 4; iterate++) { + /* iterate 0 = + unitvector[0], + unitvector[1] + * iterate 1 = + unitvector[0], - unitvector[1] + * iterate 2 = - unitvector[0], + unitvector[1] + * iterate 3 = - unitvector[0], - unitvector[1] + */ + +// System.out.println("Vectors: \n" + unitVectors[0][0] + " " + unitVectors[0][1] + "\n" + unitVectors[1][0] + " " + unitVectors[1][1]); + + double[] angle = { + Math.acos((iterate < 2 ? 1 : -1) * unitVectors[0][0] * (iterate % 2 == 0 ? 1 : -1) * unitVectors[1][0] + (iterate < 2 ? 1 : -1) * unitVectors[0][1] * (iterate % 2 == 0 ? 1 : -1) * unitVectors[1][1]), + Math.acos((iterate < 2 ? 1 : -1) * unitVectors[0][0] * unitVectors[2][0] + (iterate < 2 ? 1 : -1) * unitVectors[0][1] * unitVectors[2][1]), + Math.acos((iterate % 2 == 0 ? 1 : -1) * unitVectors[1][0] * unitVectors[2][0] + (iterate % 2 == 0 ? 1 : -1) * unitVectors[1][1] * unitVectors[2][1]), + }; + Arrays.sort(angle); +// System.out.println("Angles: " + angle[0] + " " + angle[1] + " " + angle[2]); +// angle = Arrays.stream(angle) +// .map(radiansToDegrees -> radiansToDegrees * 180.0/Math.PI) +// .toArray(); +// System.out.println("Angles: " + angle[0] + " " + angle[1] + " " + angle[2]); + if (angle[0] > largestSmallAngle) { + largestSmallAngle = angle[0]; + smallestAngleValue = iterate; + } + } + + // TODO: Circumcenters that are outside the borders + + if (withinBorders(cir)) { + if (withinBorders(new double[] {realBorderPoints[0][smallestAngleValue/2][0], realBorderPoints[0][smallestAngleValue/2][1]})) { + realCircumcenters.add(new double[] {realBorderPoints[0][smallestAngleValue/2][0], realBorderPoints[0][smallestAngleValue/2][1], a, b, -1}); + + borderCircumcenterLines.moveTo(offset + cir[1] * e, // First point on the line; circumcenter + offset + cir[0] * e); + borderCircumcenterLines.lineTo(offset + realBorderPoints[0][smallestAngleValue/2][1] * e, // Second point on the line; border point + offset + realBorderPoints[0][smallestAngleValue/2][0] * e); + } +// System.out.println("smallestAngleValue = " + smallestAngleValue); + if (withinBorders(new double[] {realBorderPoints[1][smallestAngleValue%2][0], realBorderPoints[1][smallestAngleValue%2][1], lineComboRegions[1][0], c, -1})) { + realCircumcenters.add(new double[] {realBorderPoints[1][smallestAngleValue%2][0], realBorderPoints[1][smallestAngleValue%2][1], lineComboRegions[1][0], c, -1}); + + borderCircumcenterLines.moveTo(offset + realCircumcenters.get(count[0])[1] * e, // First point on the line; circumcenter + offset + realCircumcenters.get(count[0])[0] * e); + borderCircumcenterLines.lineTo(offset + realBorderPoints[1][smallestAngleValue%2][1] * e, // Second point on the line; border point + offset + realBorderPoints[1][smallestAngleValue%2][0] * e); + } + } else { // The circumcenter is outside the border + + if (smallestAngleValue/2 == 0) { // if unit vector 1 went the right way + // Check which regions are closest to the borderpoints +// double[] doubles = Arrays.stream(ints).asDoubleStream().toArray(); + double[][] distances = { + {dist(Arrays.stream(regions[a]).asDoubleStream().toArray(), realBorderPoints[0][1]), a}, + {dist(Arrays.stream(regions[b]).asDoubleStream().toArray(), realBorderPoints[0][1]), b}, + {dist(Arrays.stream(regions[c]).asDoubleStream().toArray(), realBorderPoints[0][1]), c}, + }; + System.out.println("D: \n" + distances[0][0] + "\n" + distances[1][0] + "\n" + distances[2][0] + "\n"); + Arrays.sort(distances, (num1, num2) -> Double.compare(num1[0], num2[0])); + System.out.println("D: \n" + distances[0][0] + "\n" + distances[1][0] + "\n" + distances[2][0] + "\n"); + + // Add the correct border points to the realCircumcenters ArrayList + realCircumcenters.add(new double[] {realBorderPoints[0][0][0], realBorderPoints[0][0][1], distances[0][1], distances[1][1], -1}); + realCircumcenters.add(new double[] {realBorderPoints[0][1][0], realBorderPoints[0][1][1], distances[0][1], distances[1][1], -1}); + + // Add the lines between the 2 closest borderlines + borderCircumcenterLines.moveTo(offset + realBorderPoints[0][0][1] * e, // Closest border point + offset + realBorderPoints[0][0][0] * e); + borderCircumcenterLines.lineTo(offset + realBorderPoints[0][1][1] * e, // Farthest border point + offset + realBorderPoints[0][1][0] * e); + } + if (smallestAngleValue%2 == 0) { // if unit vector 2 went the right way + + double[][] distances = { + {dist(Arrays.stream(regions[a]).asDoubleStream().toArray(), realBorderPoints[1][1]), a}, + {dist(Arrays.stream(regions[b]).asDoubleStream().toArray(), realBorderPoints[1][1]), b}, + {dist(Arrays.stream(regions[c]).asDoubleStream().toArray(), realBorderPoints[1][1]), c}, + }; + System.out.println("D: \n" + distances[0][0] + "\n" + distances[1][0] + "\n" + distances[2][0] + "\n"); + Arrays.sort(distances, (num1, num2) -> Double.compare(num1[0], num2[0])); + System.out.println("D: \n" + distances[0][0] + "\n" + distances[1][0] + "\n" + distances[2][0] + "\n"); + + + realCircumcenters.add(new double[] {realBorderPoints[1][0][0], realBorderPoints[1][0][1], distances[0][1], distances[1][1], -1}); + realCircumcenters.add(new double[] {realBorderPoints[1][1][0], realBorderPoints[1][1][1], distances[0][1], distances[1][1], -1}); + + borderCircumcenterLines.moveTo(offset + realBorderPoints[1][0][1] * e, // Closest border point + offset + realBorderPoints[1][0][0] * e); + borderCircumcenterLines.lineTo(offset + realBorderPoints[1][1][1] * e, // Farthest border point + offset + realBorderPoints[1][1][0] * e); + + } + } + } else if (num == 0) { // There are no adjacent circumcenters to this circumcenter + /* + /* TODO: Find the region that makes the largest angle with the other regions + * Make a line from the circumcenter + * + * + + double[][] regionVectors = { + unitVector(regions[a],regions[b]), + unitVector(a,b), + unitVector(a,b), + }; + + + double[] angle = { + Math.acos(unitVectors[0][0] * unitVectors[1][0] + unitVectors[0][1] * unitVectors[1][1]), + Math.acos((iterate < 2 ? 1 : -1) * unitVectors[0][0] * unitVectors[2][0] + (iterate < 2 ? 1 : -1) * unitVectors[0][1] * unitVectors[2][1]), + Math.acos((iterate % 2 == 0 ? 1 : -1) * unitVectors[1][0] * unitVectors[2][0] + (iterate % 2 == 0 ? 1 : -1) * unitVectors[1][1] * unitVectors[2][1]), + }; + + + */ + } + } + } + } + } + double[][] borderPoints = { + {0,0}, + {0,witch.map[0].length}, + {witch.map.length,witch.map[0].length}, + {witch.map.length,0}, + }; + for (double[] bor : borderPoints) { + double dMin = Integer.MAX_VALUE; + int closest = -1; + for (int r = 0; r < regions.length; r++) { + double[] reg = new double[] {regions[r][0], regions[r][1]}; + double d = dist(reg, bor); + if (d < dMin) { + closest = r; + dMin = d; + } + } + realCircumcenters.add(new double[] {bor[0], bor[1], closest, -1, -1}); + } + + for (int r = 0; r < regions.length; r++) { +// double rD = r; + Path2D newPath = new Path2D.Double(); + + ArrayList regionCircumcenters = new ArrayList(); + for (double[] circ : realCircumcenters) { + int[] circPos = Arrays.stream(circ).mapToInt(d -> (int) d).toArray(); +// for (int i : circPos) { +// System.out.print(i + " - "); +// } +// System.out.println(r); + +// if (Arrays.asList(Arrays.copyOfRange(circPos,2,5)).contains(r)) { +// regionCircumcenters.add(circ); +// System.out.println("TRUE"); + if (circ[2] == r || circ[3] == r || circ[4] == r) { + regionCircumcenters.add(circ); +// System.out.println("TRUE"); + } else { + + } + } + for (int a = 0; a < regionCircumcenters.size(); a++) { + for (int b = a+1; b < regionCircumcenters.size(); b++) { + newPath.moveTo(offset + regions[r][1] * e, offset + regions[r][0] * e); + newPath.lineTo(offset + regionCircumcenters.get(a)[1] * e, offset + regionCircumcenters.get(a)[0] * e); + newPath.lineTo(offset + regionCircumcenters.get(b)[1] * e, offset + regionCircumcenters.get(b)[0] * e); + newPath.closePath(); + g2.setColor(regionColors[r%10]); + + g2.fill(newPath); + } + } + } + if (debug) { + g2.setColor(Color.RED); + g2.setStroke(new BasicStroke(10)); + for (int[] r : regions) + g2.drawOval(offset + r[1] * e - e / 2, offset + r[0] * e - e / 2, e, e); + + g2.setColor(Color.MAGENTA); + g2.setStroke(new BasicStroke(4)); + g2.draw(circumcenterLines); + + g2.setColor(Color.ORANGE); + g2.draw(borderCircumcenterLines); + } else { + g2.setColor(Color.BLACK); + g2.setStroke(new BasicStroke(4)); + g2.draw(circumcenterLines); + g2.draw(borderCircumcenterLines); + } + + g2.setColor(this.color); + g2.setStroke(new BasicStroke(10)); + + Path2D path = new Path2D.Double(); + path.moveTo(offset + points[0][1] * e, offset + points[0][0] * e); + for (int[] p : points) { + path.lineTo(offset + p[1] * e, offset + p[0] * e); + } + path.closePath(); +// g2.fill(path); + + g2.setColor(this.color); + g2.setStroke(new BasicStroke(1)); + + + + + BufferedImage canvas = new BufferedImage(850, 600, BufferedImage.TYPE_INT_ARGB); + int c = this.color.getRGB(); + for (int x = 0; x < canvas.getWidth(); x++) { + for (int y = 0; y < canvas.getHeight(); y++) { + canvas.setRGB(x, y, c); + } + } + + + + Path2D borderLines = new Path2D.Double(); + Path2D outsideLines = new Path2D.Double(); + + borderLines.moveTo(offset, offset); + borderLines.lineTo(offset + witch.map[0].length * e, offset); + borderLines.lineTo(offset + witch.map[0].length * e, offset + witch.map.length * e); + borderLines.lineTo(offset, offset + witch.map.length * e); + borderLines.lineTo(offset, offset); + + outsideLines.moveTo(0, 0); + outsideLines.lineTo(offset * 2 + witch.map[0].length * e, 0); + outsideLines.lineTo(offset * 2 + witch.map[0].length * e, offset * 2 + witch.map.length * e); + outsideLines.lineTo(0, offset * 2 + witch.map.length * e); + outsideLines.lineTo(0, 0); + + g2.setColor(Color.BLACK); + g2.setStroke(new BasicStroke(4)); + g2.draw(borderLines); + if (!debug) { + g2.setStroke(new BasicStroke(offset*2)); + g2.draw(outsideLines); + } + } + + public MapSections(int[][] regions, Color color) { + super(); + this.regions = regions; + this.points = new int[][] { regions[0], regions[1], regions[2] }; + this.color = color; + } + + public static double dist(double[] a, double[] b) { + return (Math.sqrt(Math.pow(a[0] - b[0], 2) + Math.pow(a[1] - b[1], 2))); + } + + public static boolean withinBorders(double[] p) { + + if (p[0] < -0.001) + return false; + if (p[0] > witch.map.length + 000.1) + return false; + if (p[1] < -0.001) + return false; + if (p[1] > witch.map[0].length + 0.001) + return false; + + return true; + } + +// ---------------------------------------------------------------------------------------------- +// Circumcenter finder functions + + public static double[] unitVector(double[] a, double[] b) { + + double dx = a[0] - b[0]; + double dy = a[1] - b[1]; + + double length = Math.sqrt(Math.pow((dx), 2) + Math.pow((dy), 2)); + + return new double[] { dx / length, dy / length }; + } + + public static double[] lineFromPoints(double[] P, double[] Q) { + double[] a_b_c = { 0, 0, 0 }; + a_b_c[0] = Q[1] - P[1]; + a_b_c[1] = P[0] - Q[0]; + a_b_c[2] = a_b_c[0] * (P[0]) + a_b_c[1] * (P[1]); + return a_b_c; + } + +// Function which converts the input line to its +// perpendicular bisector. It also inputs the points +// whose mid-point lies on the bisector + public static double[] perpendicularBisectorFromLine(double[] P, double[] Q, double[] a_b_c) { + ArrayList mid_point = new ArrayList(); + + mid_point.add((P[0] + Q[0]) / 2); + mid_point.add((P[1] + Q[1]) / 2); + +// c = -bx + ay + a_b_c[2] = -a_b_c[1] * (mid_point.get(0)) + a_b_c[0] * (mid_point.get(1)); + + double temp = a_b_c[0]; + a_b_c[0] = -a_b_c[1]; + a_b_c[1] = temp; + return a_b_c; + } + +// Returns the intersection point of two lines + public static double[] lineLineIntersection(double a1, double b1, double c1, double a2, double b2, double c2) { + double[] ans = { 0, 0 }; + double determinant = a1 * b2 - a2 * b1; + if (determinant == 0) { +// The lines are parallel. This is simplified +// by returning a pair of FLT_MAX + ans[0] = Integer.MAX_VALUE; + ans[1] = Integer.MAX_VALUE; + } else { + double x = (b2 * c1 - b1 * c2) / determinant; + double y = (a1 * c2 - a2 * c1) / determinant; + ans[0] = x; + ans[1] = y; + } + return ans; + } + + public static double[] findCircumCenter(double[] P, double[] Q, double[] R) { + + // Line PQ is represented as ax + by = c + double[] a_b_c = lineFromPoints(P, Q); + +// Line QR is represented as ex + fy = g + + double[] e_f_g = lineFromPoints(Q, R); + +// Converting lines PQ and QR to perpendicular +// bisectors. After this, L = ax + by = c +// M = ex + fy = g + perpendicularBisectorFromLine(P, Q, a_b_c); + perpendicularBisectorFromLine(Q, R, e_f_g); + +// The point of intersection of L and M gives +// the circumcenter + double[] circumcenter = lineLineIntersection(a_b_c[0], a_b_c[1], a_b_c[2], e_f_g[0], e_f_g[1], e_f_g[2]); + return circumcenter; + } +}