Repository: iluwatar/java-design-patterns
Issue: Spatial Partition pattern
Labels: epic: pattern

http://gameprogrammingpatterns.com/spatial-partition.html

Issue comments:
hi @iluwatar 
I'm willing to implement this pattern.
Ok @szoeke 
@szoeke This is pretty interesting pattern, please let me know if you need help in implementing/discussing this pattern.
This issue is free for taking again
@iluwatar I'll take a stab at this
Ok @danielsiwiec 
@danielsiwiec  are you still implementing this?
@iluwatar sorry, no - I got side tracked into other things. Please take me off of it for the time being.
This issue is free for taking again
I'd like to try to implement this. This looks interesting. @iluwatar 
Ok @karmagamer 
@iluwatar I am on it. I will update you once I am finished,
@karmagamer  please let me know if you need help with implementing or something with this pattern. I would love to help
@tliecau Sure buddy, so far it's coming along fine. I will update you in a week if I am stuck or need help.
Hi, is this done? 
I have been working on something for the last few days and it is working...if it's not done can I submit a PR?
@AnaghaSasikumar go ahead. My implementation is working but I haven't had time to follow the PR guidelines and re-write my implementation. 
Ok sure @karmagamer i'll give it a shot then 👍😀
PR #797
Updated: #828 

Pull request review comments:

Patch that resolved the issue:
diff --git a/pom.xml b/pom.xml
index 84cf41535a7a..d5aba817058c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -164,6 +164,7 @@
         <module>ambassador</module>
 	<module>acyclic-visitor</module>
 	<module>collection-pipeline</module>
+	<module>spatial-partition</module>
     </modules>
 
     <repositories>
diff --git a/spatial-partition/README.md b/spatial-partition/README.md
new file mode 100644
index 000000000000..e4270e50b1e0
--- /dev/null
+++ b/spatial-partition/README.md
@@ -0,0 +1,54 @@
+---
+layout: pattern
+title: Spatial Partition
+folder: spatial-partition
+permalink: /patterns/spatial-partition/
+categories: Game Programming pattern/Optimisation pattern
+tags:
+ - Java
+ - Difficulty-Intermediate
+---
+
+## Intent
+As explained in the book [Game Programming Patterns](http://gameprogrammingpatterns.com/spatial-partition.html) by Bob Nystrom, spatial partition pattern helps to 
+
+> efficiently locate objects by storing them in a data structure organized by their positions.
+
+## Applicability
+This pattern can be used:
+* When you need to keep track of a large number of objects' positions, which are getting updated every frame.
+* When it is acceptable to trade memory for speed, since creating and updating data structure will use up extra memory.
+
+## Explanation
+Say, you are building a war game with hundreds, or maybe even thousands of players, who are clashing on the battle field. Each player's position is getting updated every frame. The simple way to handle all interactions taking place on the field is to check each player's position against every other player's position:
+
+```java
+public void handleMeLee(Unit units[], int numUnits) {
+  for (int a = 0; a < numUnits - 1; a++)
+  {
+    for (int b = a + 1; b < numUnits; b++)
+    {
+      if (units[a].position() == units[b].position())
+      {
+        handleAttack(units[a], units[b]);
+      }
+    }
+  }
+}
+```
+
+This will include a lot of unnecessary checks between players which are too far apart to have any influence on each other. The nested loops gives this operation an O(n^2) complexity, which has to be performed every frame since many of the objects on the field may be moving each frame.
+The idea behind the Spatial Partition design pattern is to enable quick location of objects using a data structure that is organised by their positions, so when performing an operation like the one above, every object's position need not be checked against all other objects' positions. The data structure can be used to store moving and static objects, though in order to keep track of the moving objects, their positions will have to be reset each time they move. This would mean having to create a new instance of the data structure each time an object moves, which would use up additional memory. The common data structures used for this design pattern are:
+
+* Grid
+* Quad tree
+* k-d tree
+* BSP
+* Boundary volume hierarchy
+
+In our implementation, we use the Quadtree data structure which will reduce the time complexity of finding the objects within a certain range from O(n^2) to O(nlogn), decreasing the computations required significantly in case of large number of objects.
+
+## Credits
+* [Game Programming Patterns/Spatial Partition](http://gameprogrammingpatterns.com/spatial-partition.html) by Bob Nystrom
+* [Quadtree tutorial](https://www.youtube.com/watch?v=OJxEcs0w_kE) by Daniel Schiffman
+
diff --git a/spatial-partition/pom.xml b/spatial-partition/pom.xml
new file mode 100644
index 000000000000..4b42ea6c3220
--- /dev/null
+++ b/spatial-partition/pom.xml
@@ -0,0 +1,40 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <!--
+    The MIT License
+    Copyright (c) 2014-2016 Ilkka Seppälä
+    Permission is hereby granted, free of charge, to any person obtaining a copy
+    of this software and associated documentation files (the "Software"), to deal
+    in the Software without restriction, including without limitation the rights
+    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+    copies of the Software, and to permit persons to whom the Software is
+    furnished to do so, subject to the following conditions:
+    The above copyright notice and this permission notice shall be included in
+    all copies or substantial portions of the Software.
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+    THE SOFTWARE.
+-->
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>com.iluwatar</groupId>
+    <artifactId>java-design-patterns</artifactId>
+    <version>1.21.0-SNAPSHOT</version>
+  </parent>
+  <artifactId>spatial-partition</artifactId>
+  <dependencies>
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-api</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-engine</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/spatial-partition/src/main/java/com/iluwatar/spatialpartition/App.java b/spatial-partition/src/main/java/com/iluwatar/spatialpartition/App.java
new file mode 100644
index 000000000000..2928b41fe654
--- /dev/null
+++ b/spatial-partition/src/main/java/com/iluwatar/spatialpartition/App.java
@@ -0,0 +1,136 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014-2016 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package com.iluwatar.spatialpartition;
+
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Random;
+
+/**
+ * <p>The idea behind the <b>Spatial Partition</b> design pattern is to enable efficient location of objects 
+ * by storing them in a data structure that is organised by their positions. This is especially useful in the 
+ * gaming world, where one may need to look up all the objects within a certain boundary, or near a certain 
+ * other object, repeatedly. The data structure can be used to store moving and static objects, though in order 
+ * to keep track of the moving objects, their positions will have to be reset each time they move. This would 
+ * mean having to create a new instance of the data structure each frame, which would use up additional memory, 
+ * and so this pattern should only be used if one does not mind trading memory for speed and the number of 
+ * objects to keep track of is large to justify the use of the extra space.</p>
+ * <p>In our example, we use <b>{@link QuadTree} data structure</b> which divides into 4 (quad) sub-sections when 
+ * the number of objects added to it exceeds a certain number (int field capacity). There is also a 
+ * <b>{@link Rect}</b> class to define the boundary of the quadtree. We use an abstract class <b>{@link Point}</b> 
+ * with x and y coordinate fields and also an id field so that it can easily be put and looked up in the hashtable. 
+ * This class has abstract methods to define how the object moves (move()), when to check for collision with any 
+ * object (touches(obj)) and how to handle collision (handleCollision(obj)), and will be extended by any object 
+ * whose position has to be kept track of in the quadtree. The <b>{@link SpatialPartitionGeneric}</b> abstract class 
+ * has 2 fields - a hashtable containing all objects (we use hashtable for faster lookups, insertion and deletion) 
+ * and a quadtree, and contains an abstract method which defines how to handle interactions between objects using 
+ * the quadtree.</p>
+ * <p>Using the quadtree data structure will reduce the time complexity of finding the objects within a
+ * certain range from <b>O(n^2) to O(nlogn)</b>, increasing the speed of computations immensely in case of
+ * large number of objects, which will have a positive effect on the rendering speed of the game.</p>
+ */
+
+public class App {
+
+  static void noSpatialPartition(int height, int width, 
+        int numOfMovements, Hashtable<Integer, Bubble> bubbles) {
+    ArrayList<Point> bubblesToCheck = new ArrayList<Point>();
+    for (Enumeration<Integer> e = bubbles.keys(); e.hasMoreElements();) {
+      bubblesToCheck.add(bubbles.get(e.nextElement())); //all bubbles have to be checked for collision for all bubbles
+    }
+
+        //will run numOfMovement times or till all bubbles have popped
+    while (numOfMovements > 0 && !bubbles.isEmpty()) {
+      for (Enumeration<Integer> e = bubbles.keys(); e.hasMoreElements();) {
+        Integer i = e.nextElement();
+        //bubble moves, new position gets updated, collisions checked with all bubbles in bubblesToCheck
+        bubbles.get(i).move();  
+        bubbles.replace(i, bubbles.get(i));
+        bubbles.get(i).handleCollision(bubblesToCheck, bubbles);
+      }
+      numOfMovements--;
+    }
+    for (Integer key : bubbles.keySet()) {
+      //bubbles not popped
+      System.out.println("Bubble " + key + " not popped");
+    }
+  }
+
+  static void withSpatialPartition(int height, int width, 
+        int numOfMovements, Hashtable<Integer, Bubble> bubbles) {
+    //creating quadtree
+    Rect rect = new Rect(width / 2,height / 2,width,height);
+    QuadTree qTree = new QuadTree(rect, 4);
+    
+    //will run numOfMovement times or till all bubbles have popped
+    while (numOfMovements > 0 && !bubbles.isEmpty()) {
+      //quadtree updated each time
+      for (Enumeration<Integer> e = bubbles.keys(); e.hasMoreElements();) {
+        qTree.insert(bubbles.get(e.nextElement()));
+      }
+      for (Enumeration<Integer> e = bubbles.keys(); e.hasMoreElements();) {
+        Integer i = e.nextElement();
+        //bubble moves, new position gets updated, quadtree used to reduce computations
+        bubbles.get(i).move();  
+        bubbles.replace(i, bubbles.get(i));
+        SpatialPartitionBubbles sp = new SpatialPartitionBubbles(bubbles, qTree);
+        sp.handleCollisionsUsingQt(bubbles.get(i));
+      }
+      numOfMovements--;
+    }
+    for (Integer key : bubbles.keySet()) {
+      //bubbles not popped
+      System.out.println("Bubble " + key + " not popped");
+    }
+  }
+  
+  /**
+   * Program entry point.
+   *
+   * @param args command line args
+   */
+
+  public static void main(String[] args) {
+    Hashtable<Integer, Bubble> bubbles1 = new Hashtable<Integer, Bubble>();
+    Hashtable<Integer, Bubble> bubbles2 = new Hashtable<Integer, Bubble>();
+    Random rand = new Random();
+    for (int i = 0; i < 10000; i++) {
+      Bubble b = new Bubble(rand.nextInt(300), rand.nextInt(300), i, rand.nextInt(2) + 1);
+      bubbles1.put(i, b);
+      bubbles2.put(i, b);
+      System.out.println("Bubble " + i + " with radius " + b.radius + " added at (" + b.x + "," + b.y + ")");
+    }
+
+    long start1 = System.currentTimeMillis();
+    App.noSpatialPartition(300,300,20,bubbles1);
+    long end1 = System.currentTimeMillis();
+    long start2 = System.currentTimeMillis();
+    App.withSpatialPartition(300,300,20,bubbles2);
+    long end2 = System.currentTimeMillis();
+    System.out.println("Without spatial partition takes " + (end1 - start1) + "ms");
+    System.out.println("With spatial partition takes " + (end2 - start2) + "ms");
+  }
+}
+
diff --git a/spatial-partition/src/main/java/com/iluwatar/spatialpartition/Bubble.java b/spatial-partition/src/main/java/com/iluwatar/spatialpartition/Bubble.java
new file mode 100644
index 000000000000..ade1829adc19
--- /dev/null
+++ b/spatial-partition/src/main/java/com/iluwatar/spatialpartition/Bubble.java
@@ -0,0 +1,77 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014-2016 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package com.iluwatar.spatialpartition;
+
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.Random;
+
+/**
+ * Bubble class extends Point. In this example, we create several bubbles in the field,
+ * let them move and keep track of which ones have popped and which ones remain.
+ */
+
+public class Bubble extends Point<Bubble> {
+
+  final int radius;
+
+  Bubble(int x, int y, int id, int radius) {
+    super(x,y,id);
+    this.radius = radius;
+  }
+
+  void move() {
+    Random rand = new Random();
+    //moves by 1 unit in either direction
+    this.x += rand.nextInt(3) - 1;
+    this.y += rand.nextInt(3) - 1;
+  }
+
+  boolean touches(Bubble b) {
+    //distance between them is greater than sum of radii (both sides of equation squared)
+    return (this.x - b.x) * (this.x - b.x) + (this.y - b.y) * (this.y - b.y)
+                <= (this.radius + b.radius) * (this.radius + b.radius);
+  }
+
+  void pop(Hashtable<Integer, Bubble> allBubbles) {
+    System.out.println("Bubble " + this.id + " popped at (" + this.x + "," + this.y + ")!");
+    allBubbles.remove(this.id);
+  }
+
+  void handleCollision(ArrayList<Point> bubblesToCheck, Hashtable<Integer, Bubble> allBubbles) {
+    boolean toBePopped = false; //if any other bubble collides with it, made true
+    for (int i = 0; i < bubblesToCheck.size(); i++) {
+      Integer otherId = bubblesToCheck.get(i).id;
+      if (allBubbles.get(otherId) != null && //the bubble hasn't been popped yet
+                    this.id != otherId && //the two bubbles are not the same
+                    this.touches(allBubbles.get(otherId))) { //the bubbles touch
+        allBubbles.get(otherId).pop(allBubbles);
+        toBePopped = true;
+      }
+    }
+    if (toBePopped) {
+      this.pop(allBubbles);
+    }
+  }
+}
diff --git a/spatial-partition/src/main/java/com/iluwatar/spatialpartition/Point.java b/spatial-partition/src/main/java/com/iluwatar/spatialpartition/Point.java
new file mode 100644
index 000000000000..24553a6dd6a0
--- /dev/null
+++ b/spatial-partition/src/main/java/com/iluwatar/spatialpartition/Point.java
@@ -0,0 +1,66 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014-2016 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package com.iluwatar.spatialpartition;
+
+import java.util.ArrayList;
+import java.util.Hashtable;
+
+/**
+ * The abstract Point class which will be extended by any object in the field
+ * whose location has to be kept track of. Defined by x,y coordinates and an id
+ * for easy hashing into hashtable.
+ * @param <T> T will be type subclass
+ */
+
+public abstract class Point<T> {
+
+  public int x; 
+  public int y; 
+  public final int id;
+  
+  Point(int x, int y, int id) {
+    this.x = x;
+    this.y = y;
+    this.id = id;
+  }
+
+  /**
+   * defines how the object moves
+   */
+  abstract void move();
+  
+  /**
+   * defines conditions for interacting with an object obj
+   * @param obj is another object on field which also extends Point
+   * @return whether the object can interact with the other or not
+   */
+  abstract boolean touches(T obj);
+  
+  /**
+   * handling interactions/collisions with other objects
+   * @param pointsToCheck contains the objects which need to be checked
+   * @param allPoints contains hashtable of all points on field at this time
+   */
+  abstract void handleCollision(ArrayList<Point> pointsToCheck, Hashtable<Integer, T> allPoints);
+}
diff --git a/spatial-partition/src/main/java/com/iluwatar/spatialpartition/QuadTree.java b/spatial-partition/src/main/java/com/iluwatar/spatialpartition/QuadTree.java
new file mode 100644
index 000000000000..072468ce80d4
--- /dev/null
+++ b/spatial-partition/src/main/java/com/iluwatar/spatialpartition/QuadTree.java
@@ -0,0 +1,115 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014-2016 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package com.iluwatar.spatialpartition;
+
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+/**
+ * The quadtree data structure is being used to keep track of the objects' locations.
+ * It has the insert(Point) and query(range) methods to insert a new object and find
+ * the objects within a certain (rectangular) range respectively.
+ */
+
+public class QuadTree {
+  Rect boundary;
+  int capacity;
+  boolean divided;
+  Hashtable<Integer, Point> points;
+  QuadTree northwest;
+  QuadTree northeast;
+  QuadTree southwest;
+  QuadTree southeast;
+
+  QuadTree(Rect boundary, int capacity) {
+    this.boundary = boundary;
+    this.capacity = capacity;
+    this.divided = false;
+    this.points = new Hashtable<Integer, Point>();
+    this.northwest = null; 
+    this.northeast = null; 
+    this.southwest = null; 
+    this.southeast = null;
+  }
+
+  void insert(Point p) {
+    if (!this.boundary.contains(p)) {
+      return;
+    } else {
+      if (this.points.size() < this.capacity) {
+        points.put(p.id, p);
+      } else {
+        if (!this.divided) {
+          this.divide();
+        }
+
+        if (this.northwest.boundary.contains(p)) {
+          this.northwest.insert(p);
+        } else if (this.northeast.boundary.contains(p)) {
+          this.northeast.insert(p);
+        } else if (this.southwest.boundary.contains(p)) {
+          this.southwest.insert(p);
+        } else if (this.southeast.boundary.contains(p)) {
+          this.southeast.insert(p);
+        }
+      }
+    }
+  }
+
+  void divide() {
+    Rect nw = new Rect(this.boundary.x - this.boundary.width / 4, this.boundary.y + this.boundary.height / 4, 
+          this.boundary.width / 2, this.boundary.height / 2);
+    this.northwest = new QuadTree(nw , this.capacity);
+    Rect ne = new Rect(this.boundary.x + this.boundary.width / 4, this.boundary.y + this.boundary.height / 4, 
+          this.boundary.width / 2, this.boundary.height / 2);
+    this.northeast = new QuadTree(ne , this.capacity);
+    Rect sw = new Rect(this.boundary.x - this.boundary.width / 4, this.boundary.y - this.boundary.height / 4, 
+          this.boundary.width / 2, this.boundary.height / 2);
+    this.southwest = new QuadTree(sw , this.capacity);
+    Rect se = new Rect(this.boundary.x + this.boundary.width / 4, this.boundary.y - this.boundary.height / 4, 
+          this.boundary.width / 2, this.boundary.height / 2);
+    this.southeast = new QuadTree(se , this.capacity);
+    this.divided = true;
+  }
+
+  ArrayList<Point> query(Rect r, ArrayList<Point> relevantPoints) {
+    //could also be a circle instead of a rectangle
+    if (this.boundary.intersects(r)) {
+      for (Enumeration<Integer> e = this.points.keys(); e.hasMoreElements();) {
+        Integer i = e.nextElement();
+        if (r.contains(this.points.get(i))) {
+          relevantPoints.add(this.points.get(i));
+        }
+      }
+      if (this.divided) {
+        this.northwest.query(r, relevantPoints);
+        this.northeast.query(r, relevantPoints);
+        this.southwest.query(r, relevantPoints);
+        this.southeast.query(r, relevantPoints);
+      }
+    }
+    return relevantPoints;
+  }
+}
diff --git a/spatial-partition/src/main/java/com/iluwatar/spatialpartition/Rect.java b/spatial-partition/src/main/java/com/iluwatar/spatialpartition/Rect.java
new file mode 100644
index 000000000000..309d88ba183a
--- /dev/null
+++ b/spatial-partition/src/main/java/com/iluwatar/spatialpartition/Rect.java
@@ -0,0 +1,58 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014-2016 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package com.iluwatar.spatialpartition;
+
+/**
+ * The Rect class helps in defining the boundary of the quadtree and is also used to
+ * define the range within which objects need to be found in our example.
+ */
+
+public class Rect {
+  int x; 
+  int y; 
+  int width;
+  int height;
+
+  //(x,y) - centre of rectangle
+
+  Rect(int x, int y, int width, int height) {
+    this.x = x;
+    this.y = y;
+    this.width = width;
+    this.height = height;
+  }
+
+  boolean contains(Point p) {
+    return p.x >= this.x - this.width / 2 && p.x <= this.x + this.width / 2
+        && p.y >= this.y - this.height / 2 && p.y <= this.y + this.height / 2;
+  }
+
+  boolean intersects(Rect other) {
+    return !(this.x + this.width / 2 <= other.x - other.width / 2 
+          || this.x - this.width / 2 >= other.x + other.width / 2 
+          || this.y + this.height / 2 <= other.y - other.height / 2 
+          || this.y - this.height / 2 >= other.y + other.height / 2);
+  }
+}
+
diff --git a/spatial-partition/src/main/java/com/iluwatar/spatialpartition/SpatialPartitionBubbles.java b/spatial-partition/src/main/java/com/iluwatar/spatialpartition/SpatialPartitionBubbles.java
new file mode 100644
index 000000000000..ec10df78d283
--- /dev/null
+++ b/spatial-partition/src/main/java/com/iluwatar/spatialpartition/SpatialPartitionBubbles.java
@@ -0,0 +1,52 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014-2016 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package com.iluwatar.spatialpartition;
+
+import java.util.ArrayList;
+import java.util.Hashtable;
+
+/**
+ * This class extends the generic SpatialPartition abstract class and is used in
+ * our example to keep track of all the bubbles that collide, pop and stay un-popped.
+ */
+
+public class SpatialPartitionBubbles extends SpatialPartitionGeneric<Bubble> {
+
+  Hashtable<Integer, Bubble> bubbles;
+  QuadTree qTree;
+
+  SpatialPartitionBubbles(Hashtable<Integer, Bubble> bubbles, QuadTree qTree) {
+    this.bubbles = bubbles;
+    this.qTree = qTree;
+  }
+
+  void handleCollisionsUsingQt(Bubble b) {
+    //finding points within area of a square drawn with centre same as centre of bubble and length = radius of bubble
+    Rect rect = new Rect(b.x, b.y, 2 * b.radius, 2 * b.radius);
+    ArrayList<Point> quadTreeQueryResult = new ArrayList<Point>();
+    this.qTree.query(rect, quadTreeQueryResult);
+    //handling these collisions
+    b.handleCollision(quadTreeQueryResult, this.bubbles);
+  }
+}
diff --git a/spatial-partition/src/main/java/com/iluwatar/spatialpartition/SpatialPartitionGeneric.java b/spatial-partition/src/main/java/com/iluwatar/spatialpartition/SpatialPartitionGeneric.java
new file mode 100644
index 000000000000..c09753553d41
--- /dev/null
+++ b/spatial-partition/src/main/java/com/iluwatar/spatialpartition/SpatialPartitionGeneric.java
@@ -0,0 +1,44 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014-2016 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package com.iluwatar.spatialpartition;
+
+import java.util.Hashtable;
+
+/**
+ * This abstract class has 2 fields, one of which is a hashtable containing all objects
+ * that currently exist on the field and a quadtree which keeps track of locations.
+ * @param <T> T will be type of object (that extends Point)
+ */
+
+public abstract class SpatialPartitionGeneric<T> {
+
+  Hashtable<Integer, T> playerPositions;
+  QuadTree qTree;
+
+  /**
+   * handles collisions for object obj using quadtree
+   * @param obj is the object for which collisions need to be checked
+   */
+  abstract void handleCollisionsUsingQt(T obj);
+}


Test patch:
diff --git a/spatial-partition/src/test/java/com/iluwatar/spatialpartition/BubbleTest.java b/spatial-partition/src/test/java/com/iluwatar/spatialpartition/BubbleTest.java
new file mode 100644
index 000000000000..ab6b6078fbf0
--- /dev/null
+++ b/spatial-partition/src/test/java/com/iluwatar/spatialpartition/BubbleTest.java
@@ -0,0 +1,84 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014-2016 Ilkka Sepp�l�
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package com.iluwatar.spatialpartition;
+
+import static org.junit.jupiter.api.Assertions.*;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import org.junit.jupiter.api.Test;
+
+/**
+* Testing methods in Bubble class.
+*/
+
+class BubbleTest {
+
+  @Test
+  void moveTest() {
+    Bubble b = new Bubble(10,10,1,2);
+    int initialX = b.x;
+    int initialY = b.y;
+    b.move();
+    //change in x and y < |2|
+    assertTrue((b.x - initialX < 2 && b.x - initialX > -2) && (b.y - initialY < 2 && b.y - initialY > -2));
+  }
+
+  @Test
+  void touchesTest() {
+    Bubble b1 = new Bubble(0,0,1,2);
+    Bubble b2 = new Bubble(1,1,2,1);
+    Bubble b3 = new Bubble(10,10,3,1);
+    //b1 touches b2 but not b3
+    assertTrue(b1.touches(b2) && !b1.touches(b3));
+  }
+
+  @Test
+  void popTest() {
+    Bubble b1 = new Bubble(10,10,1,2);
+    Bubble b2 = new Bubble(0,0,2,2);
+    Hashtable<Integer, Bubble> bubbles = new Hashtable<Integer, Bubble>();
+    bubbles.put(1, b1); 
+    bubbles.put(2, b2);
+    b1.pop(bubbles);
+    //after popping, bubble no longer in hashtable containing all bubbles
+    assertTrue(bubbles.get(1) == null && bubbles.get(2) != null);
+  }
+
+  @Test
+  void handleCollisionTest() {
+    Bubble b1 = new Bubble(0,0,1,2);
+    Bubble b2 = new Bubble(1,1,2,1);
+    Bubble b3 = new Bubble(10,10,3,1);
+    Hashtable<Integer, Bubble> bubbles = new Hashtable<Integer, Bubble>();
+    bubbles.put(1, b1); 
+    bubbles.put(2, b2); 
+    bubbles.put(3, b3);
+    ArrayList<Point> bubblesToCheck = new ArrayList<Point>();
+    bubblesToCheck.add(b2); 
+    bubblesToCheck.add(b3);
+    b1.handleCollision(bubblesToCheck, bubbles);
+    //b1 touches b2 and not b3, so b1, b2 will be popped
+    assertTrue(bubbles.get(1) == null && bubbles.get(2) == null && bubbles.get(3) != null);
+  }
+}
diff --git a/spatial-partition/src/test/java/com/iluwatar/spatialpartition/QuadTreeTest.java b/spatial-partition/src/test/java/com/iluwatar/spatialpartition/QuadTreeTest.java
new file mode 100644
index 000000000000..3191af83b3fc
--- /dev/null
+++ b/spatial-partition/src/test/java/com/iluwatar/spatialpartition/QuadTreeTest.java
@@ -0,0 +1,77 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014-2016 Ilkka Sepp�l�
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package com.iluwatar.spatialpartition;
+
+import static org.junit.jupiter.api.Assertions.*;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.Random;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Testing QuadTree class.
+ */
+
+class QuadTreeTest {
+
+  @Test
+  void queryTest() {
+    ArrayList<Point> points = new ArrayList<Point>();
+    Random rand = new Random();
+    for (int i = 0; i < 20; i++) {
+      Bubble p = new Bubble(rand.nextInt(300), rand.nextInt(300), i, rand.nextInt(2) + 1);
+      points.add(p);
+    }
+    Rect field = new Rect(150,150,300,300); //size of field
+    Rect queryRange = new Rect(70,130,100,100); //result = all points lying in this rectangle
+    //points found in the query range using quadtree and normal method is same
+    assertTrue(QuadTreeTest.quadTreeTest(points, field, queryRange).equals(QuadTreeTest.verify(points, queryRange)));
+  }
+
+  static Hashtable<Integer, Point> quadTreeTest(ArrayList<Point> points, Rect field, Rect queryRange) {
+    //creating quadtree and inserting all points
+    QuadTree qTree = new QuadTree(field, 4);
+    for (int i = 0; i < points.size(); i++) {
+      qTree.insert(points.get(i));
+    }
+
+    ArrayList<Point> queryResult = qTree.query(queryRange, new ArrayList<Point>());
+    Hashtable<Integer, Point> result = new Hashtable<Integer, Point>();
+    for (int i = 0; i < queryResult.size(); i++) {
+      Point p = queryResult.get(i);
+      result.put(p.id, p);
+    }
+    return result;
+  }
+
+  static Hashtable<Integer, Point> verify(ArrayList<Point> points, Rect queryRange) {
+    Hashtable<Integer, Point> result = new Hashtable<Integer, Point>();
+    for (int i = 0; i < points.size(); i++) {
+      if (queryRange.contains(points.get(i))) {
+        result.put(points.get(i).id, points.get(i));
+      }
+    }
+    return result;
+  }
+}
diff --git a/spatial-partition/src/test/java/com/iluwatar/spatialpartition/RectTest.java b/spatial-partition/src/test/java/com/iluwatar/spatialpartition/RectTest.java
new file mode 100644
index 000000000000..c85254b5c383
--- /dev/null
+++ b/spatial-partition/src/test/java/com/iluwatar/spatialpartition/RectTest.java
@@ -0,0 +1,52 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014-2016 Ilkka Sepp�l�
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package com.iluwatar.spatialpartition;
+
+import static org.junit.jupiter.api.Assertions.*;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Testing Rect class.
+ */
+
+class RectTest {
+
+  @Test
+  void containsTest() {
+    Rect r = new Rect(10,10,20,20);
+    Bubble b1 = new Bubble(2,2,1,1);
+    Bubble b2 = new Bubble(30,30,2,1);
+    //r contains b1 and not b2
+    assertTrue(r.contains(b1) && !r.contains(b2));
+  }
+
+  @Test
+  void intersectsTest() {
+    Rect r1 = new Rect(10,10,20,20);
+    Rect r2 = new Rect(15,15,20,20);
+    Rect r3 = new Rect(50,50,20,20);
+    //r1 intersects r2 and not r3
+    assertTrue(r1.intersects(r2) && !r1.intersects(r3));
+  }
+}
diff --git a/spatial-partition/src/test/java/com/iluwatar/spatialpartition/SpatialPartitionBubblesTest.java b/spatial-partition/src/test/java/com/iluwatar/spatialpartition/SpatialPartitionBubblesTest.java
new file mode 100644
index 000000000000..4f37e2f86fc9
--- /dev/null
+++ b/spatial-partition/src/test/java/com/iluwatar/spatialpartition/SpatialPartitionBubblesTest.java
@@ -0,0 +1,58 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014-2016 Ilkka Sepp�l�
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package com.iluwatar.spatialpartition;
+
+import static org.junit.jupiter.api.Assertions.*;
+import java.util.Hashtable;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Testing SpatialPartition_Bubbles class.
+ */
+
+class SpatialPartitionBubblesTest {
+
+  @Test
+  void handleCollisionsUsingQtTest() {
+    Bubble b1 = new Bubble(10,10,1,3);
+    Bubble b2 = new Bubble(5,5,2,1);
+    Bubble b3 = new Bubble(9,9,3,1);
+    Bubble b4 = new Bubble(8,8,4,2);
+    Hashtable<Integer, Bubble> bubbles = new Hashtable<Integer, Bubble>();
+    bubbles.put(1, b1); 
+    bubbles.put(2, b2); 
+    bubbles.put(3, b3); 
+    bubbles.put(4, b4);
+    Rect r = new Rect(10,10,20,20);
+    QuadTree qt = new QuadTree(r,4);
+    qt.insert(b1); 
+    qt.insert(b2); 
+    qt.insert(b3); 
+    qt.insert(b4);
+    SpatialPartitionBubbles sp = new SpatialPartitionBubbles(bubbles, qt);
+    sp.handleCollisionsUsingQt(b1);
+    //b1 touches b3 and b4 but not b2 - so b1,b3,b4 get popped
+    assertTrue(bubbles.get(1) == null && bubbles.get(2) != null && bubbles.get(3) == null && bubbles.get(4) == null);
+  }
+}