Difference between pages "User:Rednaxela/kD-Tree" and "Wraith"

From Robowiki
< User:Rednaxela(Difference between pages)
Jump to navigation Jump to search
(Very slight speedup by using a parent reference and temporary variable rather than a stack)
 
(Restored edits authored by Wolfman dated 2019-11-09T17:52:35+00:00)
 
Line 1: Line 1:
A nice efficent small kD-Tree. It's quite fast... Feel free to use
+
{{Navbox small
 +
| title = Wraith Sub-pages
 +
| parent = Wraith
 +
| page1 = Version History
 +
| page2 = Challenge Results
 +
| page3 = Wolfman's TODO List
 +
}}
  
<code><pre>
+
Wraith is a refactor of my bot [[AgentSmithRedux]].  
/**
 
* Copyright 2009 Rednaxela
 
*
 
* This software is provided 'as-is', without any express or implied
 
* warranty. In no event will the authors be held liable for any damages
 
* arising from the use of this software.
 
*
 
* Permission is granted to anyone to use this software for any purpose,
 
* including commercial applications, and to alter it and redistribute it
 
* freely, subject to the following restrictions:
 
*
 
*    1. The origin of this software must not be misrepresented; you must not
 
*    claim that you wrote the original software. If you use this software
 
*    in a product, an acknowledgment in the product documentation would be
 
*    appreciated but is not required.
 
*
 
*    2. This notice may not be removed or altered from any source
 
*    distribution.
 
*/
 
  
package ags.utils.newtree2;
+
{{Infobox Robot
 +
| author          = [[User:Wolfman|Wolfman]]
 +
| extends        = [[AdvancedRobot]]
 +
| targeting      = Virtual Guns with Linear, Circular and Head On Targeting
 +
| movement        = [[DangerPrediction]]
 +
| current_version = 0.1
 +
| download_link  = https://drive.google.com/uc?export=download&id=1MlGa-docshYLFIc2udl5qOyXdT4xL6KF
 +
| isOpenSource    = no
 +
| isOneOnOne      = yes
 +
| isMelee        = not yet but planned
 +
}}
  
import java.util.ArrayList;
+
== Background Information ==
import java.util.Arrays;
 
import java.util.HashMap;
 
import java.util.List;
 
  
/**
+
Returning after 3 years, I wanted to have a bit of fun and restart some robocode projects. Taking [[AgentSmithRedux]] and improving upon it for fun.
* An efficent well-optimized kd-tree
 
*
 
* @author Rednaxela
 
*/
 
public class KdTree<T> {
 
    // Static variables
 
    private static final int bucketSize = 32;
 
  
    // All types
+
It is currently in very early testing and is not expected to be competitive till it has all its intended features & iteration.
    private final int dimensions;
 
    private final KdTree<T> parent;
 
  
    // Root only
+
== Strategy ==
    private final HashMap<Object, T> map;
 
    private double[] weights;
 
  
    // Leaf only
+
;How does it [[:Category:Movement|move]]?
    private double[][] locations;
 
    private int locationCount;
 
  
    // Stem only
+
An evolution of the technique I've currently called [[DangerPrediction]] from [[AgentSmith]] which is a form of minimum risk movement whereby it plans its route ahead based on incoming predicted bullet positions from the enemies. It should theoretically work exactly the same in 1v1 and melee as the only difference is more incoming bullets in melee to avoid. Still plan to do a write up of [[DangerPrediction]] once its been nailed down and is competitive in 1v1.
    private KdTree<T> left, right;
 
    private int splitDimension;
 
    private double splitValue;
 
  
    // Bounds
+
At the time of writing it will dodge HOT & linear guns at around 99+% efficiency, but does not yet take into account more advanced techniques that could be fired at it.
    private double[] minLimit, maxLimit;
 
  
    // Temporary
+
;How does it [[:Category:Targeting|fire]]?
    private Status status;
 
  
    /**
+
Its currently just got a simple Virtual Gun array at the moment choosing the best gun between various guns including Linear, Circular and Head On.
    * Extends the bounds of this node do include a new location
 
    */
 
    private final void extendBounds(double[] location) {
 
        if (minLimit == null) {
 
            minLimit = new double[dimensions];
 
            System.arraycopy(location, 0, minLimit, 0, dimensions);
 
            maxLimit = new double[dimensions];
 
            System.arraycopy(location, 0, maxLimit, 0, dimensions);
 
            return;
 
        }
 
  
        for (int i=0; i<dimensions; i++) {
+
;How does it [[Dodging Bullets|dodge bullets]]?
            if (minLimit[i] > location[i]) {
 
                minLimit[i] = location[i];
 
            }
 
            if (maxLimit[i] < location[i]) {
 
                maxLimit[i] = location[i];
 
            }
 
        }
 
    }
 
  
    /**
+
See Movement above!
    * Find the widest axis of the bounds of this node
 
    */
 
    private final int findWidestAxis() {
 
        int widest = 0;
 
        double width = (maxLimit[0] - minLimit[0]);
 
        for (int i = 1; i < dimensions; i++) {
 
            double nwidth = maxLimit[i] - minLimit[i];
 
            if (nwidth > width) {
 
                widest = i;
 
                width = nwidth;
 
            }
 
        }
 
        return widest;
 
    }
 
  
    // Main constructor
+
== Additional Information ==
    public KdTree(int dimensions) {
 
        this.dimensions = dimensions;
 
  
        // Init as leaf
+
;Where did you get the name?
        this.locations = new double[bucketSize][];
 
        this.locationCount = 0;
 
  
        // Init as root
+
Wraiths can only be hit by magical weapons! ;)
        this.map = new HashMap<Object, T>();
 
        this.weights = new double[dimensions];
 
        Arrays.fill(this.weights, 1.0);
 
        this.parent = null;
 
    }
 
  
    // Child constructor
+
== Credits ==
    private KdTree(KdTree<T> parent, boolean right) {
 
        this.dimensions = parent.dimensions;
 
  
        // Init as leaf
+
Currently contains the source code for Raiko Micro's gun, but it is disabled as it was required for MC2K7 challenge testing.
        this.locations = new double[bucketSize][];
 
        this.locationCount = 0;
 
  
        // Init as non-root
+
== Thanks To ==
        this.map = null;
 
        this.parent = parent;
 
    }
 
  
    /**
+
Everyone who contributes to the RoboWiki. It's an awesome resource, be proud of yourselves!
    * Add a point and associated value to the tree
 
    */
 
    public static <T> void addPoint(KdTree<T> tree, double[] location, T
 
            value) {
 
        KdTree<T> cursor = tree;
 
  
        while (cursor.locations == null || cursor.locationCount >=
+
[[Category:1-vs-1_Bots|Wraith]]
            cursor.locations.length) {
 
            if (cursor.locations != null) {
 
                cursor.splitDimension = cursor.findWidestAxis();
 
                cursor.splitValue = (cursor.minLimit[cursor.splitDimension] +
 
                        cursor.maxLimit[cursor.splitDimension]) * 0.5;
 
 
 
                // Don't split node if it has no width in any axis. Double the bucket size instead
 
                if ((cursor.minLimit[cursor.splitDimension] - cursor.maxLimit[cursor.splitDimension]) == 0) {
 
                    double[][] newLocations = new double[cursor.locations.length * 2][];
 
                    System.arraycopy(cursor.locations, 0, newLocations, 0, cursor.locationCount);
 
                    cursor.locations = newLocations;
 
                    break;
 
                }
 
 
 
                // Create child leaves
 
                KdTree<T> left = new KdTree<T>(cursor, false);
 
                KdTree<T> right = new KdTree<T>(cursor, true);
 
 
 
                // Move locations into children
 
                for (double[] oldLocation : cursor.locations) {
 
                    if (oldLocation[cursor.splitDimension] > cursor.splitValue) {
 
                        // Right
 
                        right.locations[right.locationCount] = oldLocation;
 
                        right.locationCount++;
 
                        right.extendBounds(oldLocation);
 
                    }
 
                    else {
 
                        // Left
 
                        left.locations[left.locationCount] = oldLocation;
 
                        left.locationCount++;
 
                        left.extendBounds(oldLocation);
 
                    }
 
                }
 
 
 
                // Make into stem
 
                cursor.left = left;
 
                cursor.right = right;
 
                cursor.locations = null;
 
            }
 
 
 
            cursor.extendBounds(location);
 
 
 
            if (location[cursor.splitDimension] > cursor.splitValue) {
 
                cursor = cursor.right;
 
            }
 
            else {
 
                cursor = cursor.left;
 
            }
 
        }
 
 
 
        cursor.locations[cursor.locationCount] = location;
 
        cursor.locationCount++;
 
        cursor.extendBounds(location);
 
 
 
        tree.map.put(location, value);
 
    }
 
 
 
    /**
 
    * Enumeration representing the status of a node during the running
 
    */
 
    private static enum Status {
 
        NONE,
 
        LEFTVISITED,
 
        RIGHTVISITED,
 
        ALLVISITED
 
    }
 
 
 
    /**
 
    * Stores a distance and value to output
 
    */
 
    public static class Entry<T> {
 
        public final double distance;
 
        public final T value;
 
        private Entry(double distance, T value) {
 
            this.distance = distance;
 
            this.value = value;
 
        }
 
    }
 
 
 
    /**
 
    * Calculates the nearest 'count' points to 'location', with an arbitrary weighting on dimensions
 
    */
 
    public static <T> List<Entry<T>> nearestNeighbor(KdTree<T> tree,
 
            double[] location, int count, double[] weights) {
 
        tree.weights = weights;
 
        return nearestNeighbor(tree, location, count);
 
    }
 
 
 
    /**
 
    * Calculates the nearest 'count' points to 'location'
 
    */
 
    public static <T> List<Entry<T>> nearestNeighbor(KdTree<T> tree,
 
            double[] location, int count) {
 
        KdTree<T> cursor = tree;
 
        cursor.status = Status.NONE;
 
        double range = Double.POSITIVE_INFINITY;
 
        ResultHeap resultHeap = new ResultHeap(count);
 
 
 
        do {
 
            if (cursor.status == Status.ALLVISITED) {
 
                // At a fully visited part. Move up the tree
 
                cursor = cursor.parent;
 
                continue;
 
            }
 
 
 
            if (cursor.status == Status.NONE && cursor.locations != null) {
 
                // At a leaf. Use the data.
 
                for (int i=0; i<cursor.locationCount; i++) {
 
                    double dist = sqrPointDist(cursor.locations[i], location, tree.weights);
 
                    resultHeap.addValue(dist, cursor.locations[i]);
 
                }
 
                range = resultHeap.getMaxDist();
 
 
 
                if (cursor.parent == null) {
 
                    break;
 
                }
 
                cursor = cursor.parent;
 
                continue;
 
            }
 
 
 
            // Going to descend
 
            KdTree<T> nextCursor = null;
 
            if (cursor.status == Status.NONE) {
 
                // At a fresh node, descend the most probably useful direction
 
                if (location[cursor.splitDimension] > cursor.splitValue) {
 
                    // Descend right
 
                    nextCursor = cursor.right;
 
                    cursor.status = Status.RIGHTVISITED;
 
                }
 
                else {
 
                    // Descend left;
 
                    nextCursor = cursor.left;
 
                    cursor.status = Status.LEFTVISITED;
 
                }
 
            }
 
            else if (cursor.status == Status.LEFTVISITED) {
 
                // Left node visited, descend right.
 
                nextCursor = cursor.right;
 
                cursor.status = Status.ALLVISITED;
 
            }
 
            else if (cursor.status == Status.RIGHTVISITED) {
 
                // Right node visited, descend left.
 
                nextCursor = cursor.left;
 
                cursor.status = Status.ALLVISITED;
 
            }
 
 
 
            // Check if it's worth descending. Assume it is if it's sibling has not been visited yet.
 
            if (cursor.status == Status.ALLVISITED) {
 
                if (nextCursor.locationCount == 0 || sqrPointRegionDist(location, nextCursor.minLimit, nextCursor.maxLimit, tree.weights) > range) {
 
                    continue;
 
                }
 
            }
 
 
 
            // Descend down the tree
 
            cursor = nextCursor;
 
            cursor.status = Status.NONE;
 
        } while (cursor.parent != null || cursor.status != Status.ALLVISITED);
 
 
 
        ArrayList<Entry<T>> results = new ArrayList<Entry<T>>(count);
 
        Object[] data = resultHeap.getData();
 
        double[] dist = resultHeap.getDistances();
 
        for (int i=0; i<resultHeap.values; i++) {
 
            T value = tree.map.get(data[i]);
 
            results.add(new Entry<T>(dist[i], value));
 
        }
 
 
 
        return results;
 
    }
 
 
 
    /**
 
    * Calculates the (squared euclidean) distance between two points
 
    */
 
    private static final double sqrPointDist(double[] p1, double[] p2, double[] weights) {
 
        double d = 0;
 
 
 
        for (int i=0; i<p1.length; i++) {
 
            double diff = (p1[i] - p2[i]) * weights[i];
 
            d += diff * diff;
 
        }
 
 
 
        return d;
 
    }
 
 
 
    /**
 
    * Calculates the closest (squared euclidean) distance between in a point and a bounding region
 
    */
 
    private static final double sqrPointRegionDist(double[] point, double[] min, double[] max, double[] weights) {
 
        double d = 0;
 
 
 
        for (int i=0; i<point.length; i++) {
 
            if (point[i] > max[i]) {
 
                double diff = (point[i] - max[i]) * weights[i];
 
                d += diff * diff;
 
            } else if (point[i] < min[i]) {
 
                double diff = (point[i] - min[i]) * weights[i];
 
                d += diff * diff;
 
            }
 
        }
 
 
 
        return d;
 
    }
 
 
 
    /**
 
    * Class for tracking up to 'size' closest values
 
    */
 
    private static class ResultHeap {
 
        private final Object[] data;
 
        private final double[] distance;
 
        private final int size;
 
        private int values;
 
 
 
        public ResultHeap(int size) {
 
            this.data = new Object[size+1];
 
            this.distance = new double[size+1];
 
            this.size = size;
 
            this.values = 0;
 
        }
 
 
 
        public void addValue(double dist, Object value) {
 
            if (values == size && dist >= distance[0]) {
 
                return;
 
            }
 
 
 
            // Insert value
 
            data[values] = value;
 
            distance[values] = dist;
 
            values++;
 
 
 
            // Up-Heapify
 
            for (int c = values-1, p = (c-1)/2; c != 0 && distance[c] > distance[p]; c = p, p = (c-1)/2) {
 
                Object pData = data[p];
 
                double pDist = distance[p];
 
                data[p] = data[c];
 
                distance[p] = distance[c];
 
                data[c] = pData;
 
                distance[c] = pDist;
 
            }
 
 
 
            // If too big, remove the highest value
 
            if (values > size) {
 
                // Move the last entry to the top
 
                values--;
 
                data[0] = data[values];
 
                distance[0] = distance[values];
 
 
 
                // Down-Heapify
 
                for (int p = 0, c = 1; c < values; p = c,c = p*2+1) {
 
                    if (c+1 < values && distance[c] < distance[c+1]) {
 
                        c++;
 
                    }
 
                    if (distance[p] < distance[c]) {
 
                        // Swap the points
 
                        Object pData = data[p];
 
                        double pDist = distance[p];
 
                        data[p] = data[c];
 
                        distance[p] = distance[c];
 
                        data[c] = pData;
 
                        distance[c] = pDist;
 
                    }
 
                    else {
 
                        break;
 
                    }
 
                }
 
            }
 
        }
 
 
 
        public double getMaxDist() {
 
            if (values < size) {
 
                return Double.POSITIVE_INFINITY;
 
            }
 
            return distance[0];
 
        }
 
 
 
        public Object[] getData() {
 
            return data;
 
        }
 
 
 
        public double[] getDistances() {
 
            return distance;
 
        }
 
    }
 
}
 
 
 
</pre></code>
 

Revision as of 01:21, 25 April 2020

Wraith Sub-pages:
Version History - Challenge Results - Wolfman's TODO List

Wraith is a refactor of my bot AgentSmithRedux.

Wraith
Author(s) Wolfman
Extends AdvancedRobot
Targeting Virtual Guns with Linear, Circular and Head On Targeting
Movement DangerPrediction
Current Version 0.1
Download

Background Information

Returning after 3 years, I wanted to have a bit of fun and restart some robocode projects. Taking AgentSmithRedux and improving upon it for fun.

It is currently in very early testing and is not expected to be competitive till it has all its intended features & iteration.

Strategy

How does it move?

An evolution of the technique I've currently called DangerPrediction from AgentSmith which is a form of minimum risk movement whereby it plans its route ahead based on incoming predicted bullet positions from the enemies. It should theoretically work exactly the same in 1v1 and melee as the only difference is more incoming bullets in melee to avoid. Still plan to do a write up of DangerPrediction once its been nailed down and is competitive in 1v1.

At the time of writing it will dodge HOT & linear guns at around 99+% efficiency, but does not yet take into account more advanced techniques that could be fired at it.

How does it fire?

Its currently just got a simple Virtual Gun array at the moment choosing the best gun between various guns including Linear, Circular and Head On.

How does it dodge bullets?

See Movement above!

Additional Information

Where did you get the name?

Wraiths can only be hit by magical weapons! ;)

Credits

Currently contains the source code for Raiko Micro's gun, but it is disabled as it was required for MC2K7 challenge testing.

Thanks To

Everyone who contributes to the RoboWiki. It's an awesome resource, be proud of yourselves!