From 30b5d89ddeb6af3ab12c1afb76a46acdb6bb4bc6 Mon Sep 17 00:00:00 2001 From: boy0001 Date: Sat, 18 Jul 2015 02:50:32 +1000 Subject: [PATCH] More plot analysis --- pom.xml | 7 +- .../com/intellectualcrafters/plot/PS.java | 39 +- .../plot/commands/DebugExec.java | 13 +- .../plot/commands/Rate.java | 2 +- .../plot/commands/list.java | 11 - .../plot/config/Settings.java | 3 +- .../plot/generator/BukkitHybridUtils.java | 43 +- .../plot/object/Plot.java | 16 + .../plot/object/PlotAnalysis.java | 440 +++++++++++++++++- src/main/resources/plugin.yml | 6 - 10 files changed, 510 insertions(+), 70 deletions(-) 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