diff --git a/pom.xml b/pom.xml
index 2952f421c..e37f58efd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -8,7 +8,7 @@
UTF-8
PlotSquared
- 2.12.9
+ 2.12.11
PlotSquared
jar
@@ -104,6 +104,11 @@
BarAPI
2.0
+
+ org.apache.commons
+ commons-math3
+ 3.2
+
junit
junit
diff --git a/src/main/java/com/intellectualcrafters/plot/PS.java b/src/main/java/com/intellectualcrafters/plot/PS.java
index 737eef604..68bdeb493 100644
--- a/src/main/java/com/intellectualcrafters/plot/PS.java
+++ b/src/main/java/com/intellectualcrafters/plot/PS.java
@@ -55,6 +55,7 @@ import com.intellectualcrafters.plot.generator.SquarePlotManager;
import com.intellectualcrafters.plot.generator.SquarePlotWorld;
import com.intellectualcrafters.plot.listeners.APlotListener;
import com.intellectualcrafters.plot.object.Plot;
+import com.intellectualcrafters.plot.object.PlotAnalysis;
import com.intellectualcrafters.plot.object.PlotBlock;
import com.intellectualcrafters.plot.object.PlotCluster;
import com.intellectualcrafters.plot.object.PlotGenerator;
@@ -1230,15 +1231,24 @@ public class PS {
options.put("mob_pathfinding", Settings.MOB_PATHFINDING_DEFAULT);
// Clearing + Expiry
+ options.put("clear.fastmode", Settings.ENABLE_CLUSTERS);
+ options.put("clear.on.ban", false);
options.put("clear.auto.enabled", false);
options.put("clear.auto.days", 365);
- options.put("clear.check-disk", Settings.AUTO_CLEAR_CHECK_DISK);
- options.put("clear.on.ban", false);
- options.put("clear.fastmode", Settings.ENABLE_CLUSTERS);
options.put("clear.auto.clear-interval-seconds", Settings.CLEAR_INTERVAL);
- options.put("clear.keep-if-modified", Settings.MIN_BLOCKS_CHANGED);
+ options.put("clear.auto.calibration.changes", 64);
+ options.put("clear.auto.calibration.faces", 32);
+ options.put("clear.auto.calibration.data", 1);
+ options.put("clear.auto.calibration.air", 32);
+ options.put("clear.auto.calibration.variety", 1);
+ options.put("clear.auto.calibration.changes_sd", 64);
+ options.put("clear.auto.calibration.faces_sd", 32);
+ options.put("clear.auto.calibration.data_sd", 1);
+ options.put("clear.auto.calibration.air_sd", 32);
+ options.put("clear.auto.calibration.variety_sd", 1);
+ options.put("clear.auto.threshold-percent", Settings.CLEAR_THRESHOLD);
options.put("clear.ignore-if-modified", Settings.MIN_BLOCKS_CHANGED_IGNORED);
-
+
// Schematics
options.put("schematics.save_path", Settings.SCHEMATIC_SAVE_PATH);
@@ -1319,13 +1329,24 @@ public class PS {
// Clearing + Expiry
Settings.FAST_CLEAR = config.getBoolean("clear.fastmode");
- Settings.AUTO_CLEAR_DAYS = config.getInt("clear.auto.days");
- Settings.AUTO_CLEAR_CHECK_DISK = config.getBoolean("clear.check-disk");
Settings.DELETE_PLOTS_ON_BAN = config.getBoolean("clear.on.ban");
+ Settings.MIN_BLOCKS_CHANGED_IGNORED = config.getInt("clear.ignore-if-modified");
+ Settings.AUTO_CLEAR_DAYS = config.getInt("clear.auto.days");
+ Settings.CLEAR_THRESHOLD = config.getInt("clear.auto.threshold-percent");
Settings.AUTO_CLEAR = config.getBoolean("clear.auto.enabled");
Settings.CLEAR_INTERVAL = config.getInt("clear.auto.clear-interval-seconds");
- Settings.MIN_BLOCKS_CHANGED = config.getInt("clear.keep-if-modified");
- Settings.MIN_BLOCKS_CHANGED_IGNORED = config.getInt("clear.ignore-if-modified");
+
+ // Clearing modifiers
+ PlotAnalysis.MODIFIERS.changes = config.getInt("clear.auto.calibration.changes");
+ PlotAnalysis.MODIFIERS.faces = config.getInt("clear.auto.calibration.faces");
+ PlotAnalysis.MODIFIERS.data = config.getInt("clear.auto.calibration.data");
+ PlotAnalysis.MODIFIERS.air = config.getInt("clear.auto.calibration.air");
+ PlotAnalysis.MODIFIERS.variety = config.getInt("clear.auto.calibration.variety");
+ PlotAnalysis.MODIFIERS.changes_sd = config.getInt("clear.auto.calibration.changes_sd");
+ PlotAnalysis.MODIFIERS.faces_sd = config.getInt("clear.auto.calibration.faces_sd");
+ PlotAnalysis.MODIFIERS.data_sd = config.getInt("clear.auto.calibration.data_sd");
+ PlotAnalysis.MODIFIERS.air_sd = config.getInt("clear.auto.calibration.air_sd");
+ PlotAnalysis.MODIFIERS.variety_sd = config.getInt("clear.auto.calibration.variety_sd");
// Schematics
Settings.SCHEMATIC_SAVE_PATH = config.getString("schematics.save_path");
diff --git a/src/main/java/com/intellectualcrafters/plot/commands/DebugExec.java b/src/main/java/com/intellectualcrafters/plot/commands/DebugExec.java
index cb52c03fc..f3b246f8c 100644
--- a/src/main/java/com/intellectualcrafters/plot/commands/DebugExec.java
+++ b/src/main/java/com/intellectualcrafters/plot/commands/DebugExec.java
@@ -63,18 +63,11 @@ public class DebugExec extends SubCommand {
final String arg = args[0].toLowerCase();
switch (arg) {
case "analyze": {
- final Plot plot = MainUtil.getPlot(player.getLocation());
- HybridUtils.manager.analyzePlot(plot, new RunnableVal() {
+ PlotAnalysis.calcOptimalModifiers(new Runnable() {
@Override
public void run() {
- List result = new ArrayList<>();
- result.add(Math.round(value.changes * 100) / 100d);
- result.add(Math.round(value.faces * 100) / 100d);
- result.add(Math.round(value.data * 100) / 100d);
- result.add(Math.round(value.air * 100) / 100d);
- result.add(Math.round(value.variety * 100) / 100d);
- Flag flag = new Flag(FlagManager.getFlag("analysis"), result);
- FlagManager.addPlotFlag(plot, flag);
+ PS.log("&cTHIS FUNCTION IS A WORK IN PROGRESS");
+ PS.log("&c - ");
}
});
return true;
diff --git a/src/main/java/com/intellectualcrafters/plot/commands/Rate.java b/src/main/java/com/intellectualcrafters/plot/commands/Rate.java
index b619e44e3..ac30675bf 100644
--- a/src/main/java/com/intellectualcrafters/plot/commands/Rate.java
+++ b/src/main/java/com/intellectualcrafters/plot/commands/Rate.java
@@ -78,7 +78,7 @@ public class Rate extends SubCommand {
});
UUID uuid = player.getUUID();
for (Plot p : plots) {
- if (p.settings.ratings == null || !p.settings.ratings.containsKey(uuid)) {
+ if ((p.settings.ratings == null || !p.settings.ratings.containsKey(uuid)) && !p.isAdded(uuid)) {
MainUtil.teleportPlayer(player, player.getLocation(), p);
MainUtil.sendMessage(player, C.RATE_THIS);
return true;
diff --git a/src/main/java/com/intellectualcrafters/plot/commands/list.java b/src/main/java/com/intellectualcrafters/plot/commands/list.java
index ae89bcc52..655729afc 100644
--- a/src/main/java/com/intellectualcrafters/plot/commands/list.java
+++ b/src/main/java/com/intellectualcrafters/plot/commands/list.java
@@ -104,17 +104,6 @@ public class list extends SubCommand {
}
public void noArgs(PlotPlayer plr) {
- // For #395
- // if (plr != null) {
- // if (EconHandler.manager != null) {
- // builder.append(getArgumentList(new String[] { "mine", "shared", "world", "all", "unowned", "unknown", "top", "", "", "forsale",}));
- // }
- // else {
- // builder.append(getArgumentList(new String[] { "mine", "shared", "world", "all", "unowned", "unknown", "top", "", ""}));
- // }
- // } else {
- // builder.append(getArgumentList(new String[] { "world", "all", "unowned", "unknown", "top", "", ""}));
- // }
MainUtil.sendMessage(plr, C.SUBCOMMAND_SET_OPTIONS_HEADER.s() + getArgumentList(getArgumentList(plr)));
}
diff --git a/src/main/java/com/intellectualcrafters/plot/config/Settings.java b/src/main/java/com/intellectualcrafters/plot/config/Settings.java
index d7150a464..3f99334f3 100644
--- a/src/main/java/com/intellectualcrafters/plot/config/Settings.java
+++ b/src/main/java/com/intellectualcrafters/plot/config/Settings.java
@@ -161,8 +161,7 @@ public class Settings {
* Days until a plot gets cleared
*/
public static int AUTO_CLEAR_DAYS = 360;
- public static boolean AUTO_CLEAR_CHECK_DISK = false;
- public static int MIN_BLOCKS_CHANGED = -1;
+ public static int CLEAR_THRESHOLD = 100;
public static int MIN_BLOCKS_CHANGED_IGNORED = -1;
public static int CLEAR_INTERVAL = 120;
/**
diff --git a/src/main/java/com/intellectualcrafters/plot/generator/BukkitHybridUtils.java b/src/main/java/com/intellectualcrafters/plot/generator/BukkitHybridUtils.java
index 486d51ebb..3d1445bd6 100644
--- a/src/main/java/com/intellectualcrafters/plot/generator/BukkitHybridUtils.java
+++ b/src/main/java/com/intellectualcrafters/plot/generator/BukkitHybridUtils.java
@@ -22,6 +22,8 @@ import org.bukkit.plugin.Plugin;
import com.intellectualcrafters.plot.BukkitMain;
import com.intellectualcrafters.plot.PS;
import com.intellectualcrafters.plot.config.C;
+import com.intellectualcrafters.plot.flag.Flag;
+import com.intellectualcrafters.plot.flag.FlagManager;
import com.intellectualcrafters.plot.object.ChunkLoc;
import com.intellectualcrafters.plot.object.Location;
import com.intellectualcrafters.plot.object.Plot;
@@ -182,18 +184,35 @@ public class BukkitHybridUtils extends HybridUtils {
// run whenDone
PlotAnalysis analysis = new PlotAnalysis();
- analysis.changes = MathMan.getMean(changes);
- analysis.faces = MathMan.getMean(faces);
- analysis.data = MathMan.getMean(data);
- analysis.air = MathMan.getMean(air);
- analysis.variety = MathMan.getMean(variety);
- analysis.complexity =
- + (analysis.changes + MathMan.getSD(changes, analysis.changes)) * PlotAnalysis.CHANGES_MODIFIER
- + (analysis.faces + MathMan.getSD(changes, analysis.faces)) * PlotAnalysis.FACES_MODIFIER
- + (analysis.data + MathMan.getSD(changes, analysis.data)) * PlotAnalysis.DATA_MODIFIER
- + (analysis.air + MathMan.getSD(changes, analysis.air)) * PlotAnalysis.AIR_MODIFIER
- + (analysis.variety + MathMan.getSD(changes, analysis.variety)) * PlotAnalysis.VARIETY_MODIFIER
- ;
+ analysis.changes = (int) (MathMan.getMean(changes) * 100);
+ analysis.faces = (int) (MathMan.getMean(faces) * 100);
+ analysis.data = (int) (MathMan.getMean(data) * 100);
+ analysis.air = (int) (MathMan.getMean(air) * 100);
+ analysis.variety = (int) (MathMan.getMean(variety) * 100);
+
+ analysis.changes_sd = (int) (MathMan.getSD(changes, analysis.changes) * 100);
+ analysis.faces_sd = (int) (MathMan.getSD(faces, analysis.faces) * 100);
+ analysis.data_sd = (int) (MathMan.getSD(data, analysis.data) * 100);
+ analysis.air_sd = (int) (MathMan.getSD(air, analysis.air) * 100);
+ analysis.variety_sd = (int) (MathMan.getSD(variety, analysis.variety) * 100);
+
+ // We'll set the flag later
+// List result = new ArrayList<>();
+// result.add(analysis.changes);
+// result.add(analysis.faces);
+// result.add(analysis.data);
+// result.add(analysis.air);
+// result.add(analysis.variety);
+//
+// result.add(analysis.changes_sd);
+// result.add(analysis.faces_sd);
+// result.add(analysis.data_sd);
+// result.add(analysis.air_sd);
+// result.add(analysis.variety_sd);
+//
+// Flag flag = new Flag(FlagManager.getFlag("analysis"), result);
+// FlagManager.addPlotFlag(plot, flag);
+
whenDone.value = analysis;
whenDone.run();
}
diff --git a/src/main/java/com/intellectualcrafters/plot/object/Plot.java b/src/main/java/com/intellectualcrafters/plot/object/Plot.java
index 3b3f8b043..db0dc62a2 100644
--- a/src/main/java/com/intellectualcrafters/plot/object/Plot.java
+++ b/src/main/java/com/intellectualcrafters/plot/object/Plot.java
@@ -317,6 +317,19 @@ public class Plot implements Cloneable {
return MainUtil.getPlotHome(this);
}
+ /**
+ * Get the average rating of the plot
+ * @return average rating as double
+ */
+ public double getAverageRating() {
+ double sum = 0;
+ Collection ratings = getRatings().values();
+ for (Rating rating : ratings) {
+ sum += rating.getAverageRating();
+ }
+ return sum / ratings.size();
+ }
+
/**
* Get the ratings associated with a plot
* - The rating object may contain multiple categories
@@ -324,6 +337,9 @@ public class Plot implements Cloneable {
*/
public HashMap getRatings() {
HashMap map = new HashMap();
+ if (settings.ratings == null) {
+ return map;
+ }
for (Entry entry : settings.ratings.entrySet()) {
map.put(entry.getKey(), new Rating(entry.getValue()));
}
diff --git a/src/main/java/com/intellectualcrafters/plot/object/PlotAnalysis.java b/src/main/java/com/intellectualcrafters/plot/object/PlotAnalysis.java
index 190952465..59ce18a39 100644
--- a/src/main/java/com/intellectualcrafters/plot/object/PlotAnalysis.java
+++ b/src/main/java/com/intellectualcrafters/plot/object/PlotAnalysis.java
@@ -1,36 +1,65 @@
package com.intellectualcrafters.plot.object;
+import java.lang.reflect.Array;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Iterator;
import java.util.List;
+import org.apache.commons.lang.mutable.MutableInt;
+
+import com.intellectualcrafters.plot.PS;
import com.intellectualcrafters.plot.flag.Flag;
import com.intellectualcrafters.plot.flag.FlagManager;
import com.intellectualcrafters.plot.generator.BukkitHybridUtils;
import com.intellectualcrafters.plot.util.TaskManager;
public class PlotAnalysis {
- public double changes;
- public double faces;
- public double data;
- public double air;
- public double variety;
+ public int changes;
+ public int faces;
+ public int data;
+ public int air;
+ public int variety;
+
+ public int changes_sd;
+ public int faces_sd;
+ public int data_sd;
+ public int air_sd;
+ public int variety_sd;
+
public double complexity;
- public static double CHANGES_MODIFIER = 32;
- public static double FACES_MODIFIER = 32;
- public static double DATA_MODIFIER = 32;
- public static double AIR_MODIFIER = 32;
- public static double VARIETY_MODIFIER = 32;
-
+ public static PlotAnalysis MODIFIERS = new PlotAnalysis();
+
public static PlotAnalysis getAnalysis(Plot plot) {
Flag flag = FlagManager.getPlotFlag(plot, "analysis");
if (flag != null) {
PlotAnalysis analysis = new PlotAnalysis();
- List values = (List) flag.getValue();
+ List values = (List) flag.getValue();
analysis.changes = values.get(0);
analysis.faces = values.get(1);
- analysis.data = values.get(3);
- analysis.air = values.get(4);
- analysis.variety = values.get(5);
+ analysis.data = values.get(2);
+ analysis.air = values.get(3);
+ analysis.variety = values.get(4);
+
+ analysis.changes_sd = values.get(5);
+ analysis.faces_sd = values.get(6);
+ analysis.data_sd = values.get(7);
+ analysis.air_sd = values.get(8);
+ analysis.variety_sd = values.get(9);
+
+ analysis.complexity =
+ + (analysis.changes) * MODIFIERS.changes
+ + (analysis.faces) * MODIFIERS.faces
+ + (analysis.data) * MODIFIERS.data
+ + (analysis.air) * MODIFIERS.air
+ + (analysis.variety) * MODIFIERS.variety
+ + (analysis.changes_sd) * MODIFIERS.changes_sd
+ + (analysis.faces_sd) * MODIFIERS.faces_sd
+ + (analysis.data_sd) * MODIFIERS.data_sd
+ + (analysis.air_sd) * MODIFIERS.air_sd
+ + (analysis.variety_sd) * MODIFIERS.variety_sd
+ ;
return analysis;
}
return null;
@@ -40,17 +69,392 @@ public class PlotAnalysis {
PlotAnalysis analysis = getAnalysis(plot);
if (analysis != null) {
whenDone.value = analysis;
- whenDone.run();
+ if (whenDone != null) whenDone.run();
return;
}
BukkitHybridUtils.manager.analyzePlot(plot, whenDone);
}
+ public static boolean running = false;
+
/**
- *
+ * This will set the optimal modifiers for the plot analysis based on the current plot ratings
+ * - Will be used to calibrate the threshold for plot clearing
* @param whenDone
*/
- public static void calcOptimalModifiers(Runnable whenDone) {
+ public static void calcOptimalModifiers(final Runnable whenDone) {
+ if (running) {
+ PS.log("Calibration task already in progress!");
+ return;
+ }
+ running = true;
+ PS.log(" - Fetching all plots");
+ final ArrayList plots = new ArrayList<>(PS.get().getPlots());
+ TaskManager.runTaskAsync(new Runnable() {
+ @Override
+ public void run() {
+ Iterator iter = plots.iterator();
+
+ PS.log(" - $1Reducing " + plots.size() + " plots to those with sufficient data");
+ while (iter.hasNext()) {
+ Plot plot = iter.next();
+ if (plot.settings.ratings == null || plot.settings.ratings.size() == 0) {
+ iter.remove();
+ }
+ }
+ PS.log(" - | Reduced to " + plots.size() + " plots");
+
+ if (plots.size() < 3) {
+ PS.log("Calibration cancelled due to insufficient comparison data, please try again later");
+ running = false;
+ return;
+ }
+
+ PS.log(" - $1Analyzing plot contents (this may take a while)");
+
+ final int[] changes = new int[plots.size()];
+ final int[] faces = new int[plots.size()];
+ final int[] data = new int[plots.size()];
+ final int[] air = new int[plots.size()];
+ final int[] variety = new int[plots.size()];
+
+ final int[] changes_sd = new int[plots.size()];
+ final int[] faces_sd = new int[plots.size()];
+ final int[] data_sd = new int[plots.size()];
+ final int[] air_sd = new int[plots.size()];
+ final int[] variety_sd = new int[plots.size()];
+
+ final int[] ratings = new int[plots.size()];
+
+ final MutableInt mi = new MutableInt(0);
+
+ Thread ratingAnalysis = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ for (;mi.intValue() < plots.size(); mi.increment()) {
+ int i = mi.intValue();
+ Plot plot = plots.get(i);
+ ratings[i] = (int) ((plot.getAverageRating() + plot.settings.ratings.size()) * 100);
+ PS.log(" | " + plot + " (rating) " + (ratings[i]));
+ }
+ }
+ });
+ ratingAnalysis.start();
+
+ final ArrayDeque plotsQueue = new ArrayDeque<>(plots);
+ Plot queuePlot;
+ while ((queuePlot = plotsQueue.poll()) != null) {
+ PS.log(" | " + queuePlot);
+ final Thread thread = Thread.currentThread();
+ analyzePlot(queuePlot, new RunnableVal() {
+ public void run() {
+ thread.notify();
+ }
+ });
+ try {
+ thread.wait();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
+ PS.log(" - $1Waiting on plot rating thread: " + ((mi.intValue() * 100) / plots.size()) + "%");
+ try {
+ ratingAnalysis.join();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ PS.log(" - $1Processing and grouping single plot analysis for bulk processing");
+ for (int i = 0; i < plots.size(); i++) {
+ Plot plot = plots.get(i);
+ PS.log(" | " + plot);
+ PlotAnalysis analysis = plot.getComplexity();
+
+ changes[i] = analysis.changes;
+ faces[i] = analysis.faces;
+ data[i] = analysis.data;
+ air[i] = analysis.air;
+ variety[i] = analysis.variety;
+
+ changes_sd[i] = analysis.changes_sd;
+ faces_sd[i] = analysis.faces_sd;
+ data_sd[i] = analysis.data_sd;
+ air_sd[i] = analysis.air_sd;
+ variety_sd[i] = analysis.variety_sd;
+ }
+
+ int[] rank_ratings = rank(ratings);
+ int n = rank_ratings.length;
+
+ PS.log(" - $1Calculating rank correlation: ");
+ PS.log(" - The analyzed plots which were processed and put into bulk data will be compared and correlated to the ranked plots");
+ PS.log(" - The calculated correlation constant will be used to calibrate the threshold for auto plot clearing");
+
+ int[] rank_changes = rank(changes);
+ int[] sd_changes = getSD(rank_changes);
+ int[] variance_changes = square(sd_changes);
+ int sum_changes = sum(variance_changes);
+ double factor_changes = getCC(n, sum_changes);
+ PlotAnalysis.MODIFIERS.changes = (int) (factor_changes * 100);
+ PS.log(" - | changes " + factor_changes);
+
+ int[] rank_faces = rank(faces);
+ int[] sd_faces = getSD(rank_faces);
+ int[] variance_faces = square(sd_faces);
+ int sum_faces = sum(variance_faces);
+ double factor_faces = getCC(n, sum_faces);
+ PlotAnalysis.MODIFIERS.faces = (int) (factor_faces * 100);
+ PS.log(" - | faces " + factor_faces);
+
+ int[] rank_data = rank(data);
+ int[] sd_data = getSD(rank_data);
+ int[] variance_data = square(sd_data);
+ int sum_data = sum(variance_data);
+ double factor_data = getCC(n, sum_data);
+ PlotAnalysis.MODIFIERS.data = (int) (factor_data * 100);
+ PS.log(" - | data " + factor_data);
+
+ int[] rank_air = rank(air);
+ int[] sd_air = getSD(rank_air);
+ int[] variance_air = square(sd_air);
+ int sum_air = sum(variance_air);
+ double factor_air = getCC(n, sum_air);
+ PlotAnalysis.MODIFIERS.air = (int) (factor_air * 100);
+ PS.log(" - | air " + factor_air);
+
+ int[] rank_variety = rank(variety);
+ int[] sd_variety = getSD(rank_variety);
+ int[] variance_variety = square(sd_variety);
+ int sum_variety = sum(variance_variety);
+ double factor_variety = getCC(n, sum_variety);
+ PlotAnalysis.MODIFIERS.variety = (int) (factor_variety * 100);
+ PS.log(" - | variety " + factor_variety);
+
+ int[] rank_changes_sd = rank(changes_sd);
+ int[] sd_changes_sd = getSD(rank_changes_sd);
+ int[] variance_changes_sd = square(sd_changes_sd);
+ int sum_changes_sd = sum(variance_changes_sd);
+ double factor_changes_sd = getCC(n, sum_changes_sd);
+ PlotAnalysis.MODIFIERS.changes_sd = (int) (factor_changes_sd * 100);
+ PS.log(" - | changes_sd " + factor_changes_sd);
+
+ int[] rank_faces_sd = rank(faces_sd);
+ int[] sd_faces_sd = getSD(rank_faces_sd);
+ int[] variance_faces_sd = square(sd_faces_sd);
+ int sum_faces_sd = sum(variance_faces_sd);
+ double factor_faces_sd = getCC(n, sum_faces_sd);
+ PlotAnalysis.MODIFIERS.faces_sd = (int) (factor_faces_sd * 100);
+ PS.log(" - | faces_sd " + factor_faces_sd);
+
+ int[] rank_data_sd = rank(data_sd);
+ int[] sd_data_sd = getSD(rank_data_sd);
+ int[] variance_data_sd = square(sd_data_sd);
+ int sum_data_sd = sum(variance_data_sd);
+ double factor_data_sd = getCC(n, sum_data_sd);
+ PlotAnalysis.MODIFIERS.data_sd = (int) (factor_data_sd * 100);
+ PS.log(" - | data_sd " + factor_data_sd);
+
+ int[] rank_air_sd = rank(air_sd);
+ int[] sd_air_sd = getSD(rank_air_sd);
+ int[] variance_air_sd = square(sd_air_sd);
+ int sum_air_sd = sum(variance_air_sd);
+ double factor_air_sd = getCC(n, sum_air_sd);
+ PlotAnalysis.MODIFIERS.air_sd = (int) (factor_air_sd * 100);
+ PS.log(" - | air_sd " + factor_air_sd);
+
+ int[] rank_variety_sd = rank(variety_sd);
+ int[] sd_variety_sd = getSD(rank_variety_sd);
+ int[] variance_variety_sd = square(sd_variety_sd);
+ int sum_variety_sd = sum(variance_variety_sd);
+ double factor_variety_sd = getCC(n, sum_variety_sd);
+ PlotAnalysis.MODIFIERS.variety_sd = (int) (factor_variety_sd * 100);
+ PS.log(" - | variety_sd " + factor_variety_sd);
+
+ // Save modifiers
+
+ PS.log(" $1Done!");
+ running = false;
+ whenDone.run();
+ }
+ });
+
+
+
+ // sort plots by popularity
+
+ // get the arrays for each modifier
+
+ // get the rankings for each modifier
+
+ /*
+ * For each modifier:
+ * - get the arrays
+ * - get the rankings
+ */
+ }
+
+ public static void logln(Object obj) {
+ System.out.println(log(obj));
+ }
+
+ public static String log(Object obj) {
+ String result = "";
+ if (obj.getClass().isArray()) {
+ String prefix = "";
+
+ for(int i=0; i) {
+ String prefix = "";
+ for (Object element : (List>) obj) {
+ result += prefix + log(element);
+ prefix = ",";
+ }
+ return "[ " + result + " ]";
+ }
+ else {
+ return obj.toString();
+ }
+ }
+
+ /**
+ * Get correllation coefficient
+ * @return
+ */
+ public static double getCC(int n, int sum) {
+ return 1 - (6 * (double) sum) / (n * (n*n - 1));
+ }
+
+ /**
+ * Sum of an array
+ * @param array
+ * @return
+ */
+ public static int sum(int[] array) {
+ int sum = 0;
+ for (int value : array ) {
+ sum += value;
+ }
+ return sum;
+ }
+
+ /**
+ * A simple array squaring algorithm
+ * - Used for calculating the variance
+ * @param array
+ * @return
+ */
+ public static int[] square(int[] array) {
+ array = array.clone();
+ for (int i = 0; i < array.length; i++) {
+ array[i] *= array[i];
+ }
+ return array;
+ }
+
+ /**
+ * An optimized lossy standard deviation algorithm
+ * @param ranks
+ * @return
+ */
+ public static int[] getSD(int[]...ranks) {
+ if (ranks.length == 0) {
+ return null;
+ }
+ int size = ranks[0].length;
+ int arrays = ranks.length;
+ int[] result = new int[size];
+ for (int j = 0; j < size; j++) {
+ int sum = 0;
+ for (int i = 0; i < ranks.length; i++) {
+ sum += ranks[i][j];
+ }
+ int mean = sum / arrays;
+ int sd = 0;
+ for (int i = 0; i < ranks.length; i++) {
+ int value = ranks[i][j];
+ sd += value < mean ? mean - value : value - mean;
+ }
+ result[j] = sd;
+ }
+ return result;
+ }
+
+ /**
+ * An optimized algorithm for ranking a very specific set of inputs
+ * - Input is an array of int with a max size of 102400
+ * - This allows for optimizations beyond any standard sorting function
+ * @param input
+ * @return
+ */
+ public static int[] rank(final int[] input) {
+ int[] cache = new int[102400];
+ int max = 0;
+ if (input.length < 102400) {
+ for (int value : input) {
+ if (value > max) {
+ max = value;
+ }
+ cache[value]++;
+ }
+ }
+ else {
+ max = cache.length - 1;
+ for (int value : input) {
+ cache[value]++;
+ }
+ }
+ int last = 0;
+ for (int i = max; i >= 0; i--) {
+ if (cache[i] != 0) {
+ cache[i] += last;
+ last = cache[i];
+ if (last == input.length) {
+ break;
+ }
+ }
+ }
+
+ int[] ranks = new int[input.length];
+ for (int i = 0; i < input.length; i++) {
+ int index = input[i];
+ ranks[i] = cache[index];
+ cache[index]--;
+ }
+ return ranks;
+ }
+
+ public static void sort(int[] input) {
+ final int SIZE = 10;
+ List[] bucket = new ArrayList[SIZE];
+ for (int i = 0; i < bucket.length; i++) {
+ bucket[i] = new ArrayList();
+ }
+ boolean maxLength = false;
+ int tmp = -1, placement = 1;
+ while (!maxLength) {
+ maxLength = true;
+ for (Integer i : input) {
+ tmp = i / placement;
+ bucket[tmp % SIZE].add(i);
+ if (maxLength && tmp > 0) {
+ maxLength = false;
+ }
+ }
+ int a = 0;
+ for (int b = 0; b < SIZE; b++) {
+ for (Integer i : bucket[b]) {
+ input[a++] = i;
+ }
+ bucket[b].clear();
+ }
+ placement *= SIZE;
+ }
}
}
diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml
index 8709a14cb..9cee46022 100644
--- a/src/main/resources/plugin.yml
+++ b/src/main/resources/plugin.yml
@@ -15,12 +15,6 @@ commands:
permission: plots.use
permission-message: "You are lacking the permission node 'plots.use'"
permissions:
- plotsquared_user_attributes:
- default: false
- plotsquared_user_attributes.disabletitles:
- default: false
- plotsquared_user_attributes.*:
- default: false
plots.admin:
children:
plots.*: true