Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

hw19 posted

  • Loading branch information...
commit a82df2899e9c93ecd2131745745a6e4f0be03e6c 1 parent 8b17fc1
Alec Goebel alecgoebel authored
90 hw19/README.md
View
@@ -0,0 +1,90 @@
+Homework 19
+=========================
+Recursion and QuadTrees
+-------------------------
+
+In this assignment, you will be fleshing out a [Quadtree](http://en.wikipedia.org/wiki/Quadtree). Quadtrees are traditionally used in graphics programming to quickly eliminate large groups of points.
+
+QuadTreeNode is already mostly a quadtree. However, in order to actually use it in a program, there should be easier ways to access the data inside the QuadTree. Specifically, we need a way to get a list of all the points in the quadtree and a way to get every rectangle (quadrents).
+
+As you add the methods in this homework, run `test_quad.py` to run the normal battery of unit tests to see if it works. Once you are completely done, you can use `./rundemo` to run a graphical demo to see your quadtree in action.
+
+> `rundemo` is a python file so can just be opened in IDLE on Windows.
+
+
+Getting the Points (get_points)
+--------------------------------
+
+Add a method `get_points` to QuadTreeNode. This method will fetch a list of every point stored in a QuadTreeNode and it's children. Since each
+
+**Requirements:**
+
+ * if there are no points, return an empty list
+ * if there is only one point, return a list with only that point in it
+ * if there is more than one point, return a list with every point
+ * the order the points are output doesn't matter
+
+**Example:**
+
+```python
+>>> qtree = QuadTreeNode(Rect(0, 0, 100, 100))
+>>> # no points
+>>> qtree.get_points()
+[]
+>>> # one point
+>>> qtree.add_point((25, 25))
+>>> qtree.get_points()
+[ (25,25) ]
+>>> # many points
+>>> qtree.add_point((75, 75))
+>>> qtree.add_point((22, 22))
+[ (25,25), (75, 75), (22, 22) ]
+```
+
+
+
+Getting Rects (quadrents)
+--------------------------------
+
+Add a method `get_rects` which fetches every rectangle out of a QuadTree. This includes the root node and its children if it has any and so on. This should be a flat list of rectangles (not lists in lists).
+
+**Requirements:**
+
+ * if there are zero/one points, return just the root rect
+ * if there is more than one point, return the root rect and all it's children
+ * if there is more than one level of nesting, return nested child.
+ * order of rects doesn't matter
+
+> **HINT:** You can use an optional `rects` parameter to keep track of all the rects as you add them. Since arrays are a reference, adding a rect to an array as you recurse is a good way to track all the values
+
+**Example:**
+
+```python
+>>> qtree = QuadTreeNode(Rect(0, 0, 100, 100))
+>>> # no points
+>>> qtree.get_rects()
+[<rect(0, 0, 100, 100)>]
+>>> # one point
+>>> qtree.add_point((10, 10))
+>>> qtree.get_rects()
+[<rect(0, 0, 100, 100)>]
+>>> # two points in different quadrents
+>>> qtree.add_point((75, 75))
+>>> qtree.get_rects()
+[<rect(0, 0, 100, 100)>, <rect(0, 0, 50, 50)>, <rect(50, 0, 50, 50)>, <rect(0, 50, 50, 50)>, <rect(50, 50, 50, 50)>]
+>>> # two points in the same quadrent
+>>> qtree.add_point((40, 40))
+>>> qtree.get_rects()
+[<rect(0, 0, 100, 100)>, <rect(0, 0, 50, 50)>, <rect(0, 0, 25, 25)>, <rect(25, 0, 25, 25)>, <rect(0, 25, 25, 25)>, <rect(25, 25, 25, 25)>, <rect(25, 0, 25, 25)>, <rect(0, 25, 25, 25)>, <rect(25, 25, 25, 25)>]
+```
+
+[Advanced] Collide Point with QuadTree (collidepoint)
+--------------------------------------------------------
+
+Add a method `collidepoint` which returns the smallest QuadTreeNode which collides with a given point.
+
+**Requirements:**
+ * if the point is not within the QuadTreeNode, return None
+ * if the QuadTreeNode is not split and the point collides, return itself
+ * if the QuadTreeNode is split, return collidepoint for the child
+
162 hw19/quad.py
View
@@ -0,0 +1,162 @@
+"""
+quad.py
+
+=========================
+Homework 19
+=========================
+Recursion and QuadTrees
+-------------------------
+
+In this assignment, you will be fleshing out a Quadtree (http://en.wikipedia.org/wiki/Quadtree). Quadtrees are traditionally used
+in graphics programming to quickly eliminate large groups of points.
+
+QuadTreeNode is already mostly a quadtree. However, in order to actually use it in a program, there should be easier ways to access the
+data inside the QuadTree. Specifically, we need a way to get a list of all the points in the quadtree and a way to get every rectangle (quadrents).
+
+As you add the methods in this homework, run `test_quad.py` to run the normal battery of unit tests to see if it works. Once you are completely done, you can use `./rundemo` to run a graphical demo to see your quadtree in action.
+
+> `rundemo` is a python file so can just be opened in IDLE on Windows.
+
+
+Getting the Points (get_points)
+--------------------------------
+
+Add a method `get_points` to QuadTreeNode. This method will fetch a list of every point stored in
+a QuadTreeNode and it's children. Since each
+
+Requirements:
+ * if there are no points, return an empty list
+ * if there is only one point, return a list with only that point in it
+ * if there is more than one point, return a list with every point
+ * the order the points are output doesn't matter
+
+Example:
+ >>> qtree = QuadTreeNode(Rect(0, 0, 100, 100))
+ >>> # no points
+ >>> qtree.get_points()
+ []
+ >>> # one point
+ >>> qtree.add_point((25, 25))
+ >>> qtree.get_points()
+ [ (25,25) ]
+ >>> # many points
+ >>> qtree.add_point((75, 75))
+ >>> qtree.add_point((22, 22))
+ [ (25,25), (75, 75), (22, 22) ]
+
+
+
+Getting Rects (quadrents)
+--------------------------------
+
+Add a method `get_rects` which fetches every rectangle out of a QuadTree. This includes the root node and its children if it has any and so on. This should be a flat list of rectangles (not lists in lists).
+
+Requirements:
+ * if there are zero/one points, return just the root rect
+ * if there is more than one point, return the root rect and all it's children
+ * if there is more than one level of nesting, return nested child.
+ * order of rects doesn't matter
+
+> HINT: You can use an optional `rects` parameter to keep track of all the rects as you add them. Since arrays are a reference, adding a rect to an array as you recurse is a good way to track all the values
+
+Example:
+ >>> qtree = QuadTreeNode(Rect(0, 0, 100, 100))
+ >>> # no points
+ >>> qtree.get_rects()
+ [<rect(0, 0, 100, 100)>]
+ >>> # one point
+ >>> qtree.add_point((10, 10))
+ >>> qtree.get_rects()
+ [<rect(0, 0, 100, 100)>]
+ >>> # two points in different quadrents
+ >>> qtree.add_point((75, 75))
+ >>> qtree.get_rects()
+ [<rect(0, 0, 100, 100)>, <rect(0, 0, 50, 50)>, <rect(50, 0, 50, 50)>, <rect(0, 50, 50, 50)>, <rect(50, 50, 50, 50)>]
+ >>> # two points in the same quadrent
+ >>> qtree.add_point((40, 40))
+ >>> qtree.get_rects()
+ [<rect(0, 0, 100, 100)>, <rect(0, 0, 50, 50)>, <rect(0, 0, 25, 25)>, <rect(25, 0, 25, 25)>, <rect(0, 25, 25, 25)>, <rect(25, 25, 25, 25)>, <rect(25, 0, 25, 25)>, <rect(0, 25, 25, 25)>, <rect(25, 25, 25, 25)>]
+
+
+[Advanced] Collide Point with QuadTree (collidepoint)
+--------------------------------------------------------
+
+Add a method `collidepoint` which returns the smallest QuadTreeNode which collides with a given point.
+
+Requirements:
+ * if the point is not within the QuadTreeNode, return None
+ * if the QuadTreeNode is not split and the point collides, return itself
+ * if the QuadTreeNode is split, return collidepoint for the child
+
+
+"""
+
+from math import ceil, floor
+
+import pygame
+from pygame.locals import *
+
+from pygame import Rect
+
+MAX_DEPTH = 10
+class QuadTreeNode(object):
+
+ def __init__(self, rect, depth = 0):
+ self.rect = rect
+ self.data = None
+ self.is_split = False
+
+ self.ne = None
+ self.nw = None
+ self.se = None
+ self.sw = None
+
+ self.depth = depth
+
+ def add_point(self, point):
+ # if we don't have data, just add it
+ if self.data is None and not self.is_split:
+ self.data = point
+ return
+ elif self.depth == MAX_DEPTH:
+ self.data = point
+ return
+
+ # if already haven't split, do that now
+ if not self.is_split:
+ prev_point = self.data
+ self.is_split = True
+
+ r = self.rect
+ w = self.rect.width / 2.0
+ h = self.rect.height / 2.0
+ d = self.depth + 1
+
+ self.nw = QuadTreeNode( Rect(r.left, r.top, floor(w), floor(h) ), d )
+ self.ne = QuadTreeNode( Rect(r.centerx, r.top, ceil(w), floor(h) ), d )
+ self.sw = QuadTreeNode( Rect(r.left, r.centery, floor(w), ceil(h) ), d )
+ self.se = QuadTreeNode( Rect(r.centerx, r.centery, ceil(w), ceil(h) ), d )
+
+ # re add the point
+ self.add_point(prev_point)
+
+ # add the point to the split
+ if self.nw.rect.collidepoint(point):
+ self.nw.add_point(point)
+ elif self.ne.rect.collidepoint(point):
+ self.ne.add_point(point)
+ elif self.sw.rect.collidepoint(point):
+ self.sw.add_point(point)
+ else:
+ self.se.add_point(point)
+
+ # def get_points(self):
+
+
+ # def get_rects(node, rects=None):
+ # if rects is None:
+ # rects = []
+
+
+ # Advanced
+ # def collidepoint(self, point):
44 hw19/rundemo
View
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+
+from math import ceil, floor
+
+import pygame
+from pygame.locals import *
+
+from pygame import Rect
+
+from quad import QuadTreeNode
+
+
+pygame.init()
+screen = pygame.display.set_mode((800, 800))
+root = QuadTreeNode(screen.get_rect())
+
+done = False
+clock = pygame.time.Clock()
+while not done:
+ for event in pygame.event.get():
+ if event.type == QUIT:
+ done = True
+ elif event.type == KEYDOWN and event.key == K_ESCAPE:
+ done = True
+ elif event.type == MOUSEBUTTONDOWN:
+ root.add_point(pygame.mouse.get_pos())
+
+ screen.fill(0)
+
+ # draw quadtree
+ if hasattr(root, "collidepoint"):
+ active = root.collidepoint(pygame.mouse.get_pos())
+ screen.fill((80,80,80), active.rect)
+
+ if hasattr(root, "get_rects"):
+ for rect in root.get_rects():
+ pygame.draw.rect(screen, (170, 170, 170), rect, 1)
+
+ if hasattr(root, "get_points"):
+ for point in root.get_points():
+ pygame.draw.circle(screen, (255,255,255), point, 3)
+
+ pygame.display.flip()
+ clock.tick(30)
129 hw19/test_quad.py
View
@@ -0,0 +1,129 @@
+#!/usr/bin/env python
+
+import math
+
+from pygame import Rect
+
+try:
+ import unittest2 as unittest
+except:
+ import unittest
+
+from quad import QuadTreeNode
+
+class QuadTreeTest(unittest.TestCase):
+
+ def setUp(self):
+ self.qtree = QuadTreeNode(Rect(0,0,100, 100))
+
+ # get_points tests
+ @unittest.skipIf(not hasattr(QuadTreeNode, "get_points"), "missing get_points")
+ def test_get_points_empty(self):
+ "if no points have been added, get_points should return an empty list"
+ self.assertItemsEqual(self.qtree.get_points(), [], "No points have been added to the quadtree, should return an empty list")
+
+ @unittest.skipIf(not hasattr(QuadTreeNode, "get_points"), "missing get_points")
+ def test_get_points_one(self):
+ "if only one point is added, a list containing that one point should be returned"
+ self.qtree.add_point((25, 25))
+ self.assertItemsEqual(self.qtree.get_points(), [(25,25)], "One point has been added, only one point should be returned")
+
+ @unittest.skipIf(not hasattr(QuadTreeNode, "get_points"), "missing get_points")
+ def test_get_points_many(self):
+ "get_points should return all points added"
+
+ self.qtree.add_point((25, 25))
+ self.qtree.add_point((75, 75))
+ self.qtree.add_point((22, 22))
+ self.assertItemsEqual(self.qtree.get_points(), [(22,22), (75,75), (25,25)], "Incorrect points returned")
+
+ # get_rects tests
+ @unittest.skipIf(not hasattr(QuadTreeNode, "get_rects"), "missing get_rects")
+ def test_get_rects_simple(self):
+ "if zero or one points have been added, get_rects should just return a list with the root's rect"
+ self.assertIn(self.qtree.rect, self.qtree.get_rects(), "root rect missing, no points")
+ self.assertEqual(1, len(self.qtree.get_rects()), "too many rects returned, no points")
+
+ self.qtree.add_point((30,30))
+ self.assertIn(self.qtree.rect, self.qtree.get_rects(), "root rect missing, one point")
+ self.assertEqual(1, len(self.qtree.get_rects()), "too many rects returned, one point")
+
+ @unittest.skipIf(not hasattr(QuadTreeNode, "get_rects"), "missing get_rects")
+ def test_get_rects_split(self):
+ "if only one split has happened, the root and it's children should be returned"
+
+ self.qtree.add_point((25,25))
+ self.qtree.add_point((75,75))
+ rects = self.qtree.get_rects()
+
+ self.assertEqual(5, len(rects), "expected 5 rects (root and children)")
+ self.assertIn(self.qtree.rect, rects, "root rect missing")
+ self.assertIn(self.qtree.nw.rect, rects, "root.nw rect missing")
+ self.assertIn(self.qtree.ne.rect, rects, "root.ne rect missing")
+ self.assertIn(self.qtree.sw.rect, rects, "root.sw rect missing")
+ self.assertIn(self.qtree.se.rect, rects, "root.se rect missing")
+
+ @unittest.skipIf(not hasattr(QuadTreeNode, "get_rects"), "missing get_rects")
+ def test_get_rects_complex(self):
+ "if many splits have occured, all rects should be returned"
+
+ self.qtree.add_point((10,10))
+ self.qtree.add_point((40,40))
+ self.qtree.add_point((75,75))
+ rects = self.qtree.get_rects()
+
+ self.assertEqual(9, len(rects), "expected 5 rects (root and children)")
+ self.assertIn(self.qtree.rect, rects, "root rect missing")
+ self.assertIn(self.qtree.nw.rect, rects, "root.nw rect missing")
+ self.assertIn(self.qtree.ne.rect, rects, "root.ne rect missing")
+ self.assertIn(self.qtree.sw.rect, rects, "root.sw rect missing")
+ self.assertIn(self.qtree.se.rect, rects, "root.se rect missing")
+ self.assertIn(self.qtree.nw.nw.rect, rects, "root.nw.nw rect missing")
+ self.assertIn(self.qtree.nw.ne.rect, rects, "root.nw.ne rect missing")
+ self.assertIn(self.qtree.nw.sw.rect, rects, "root.nw.sw rect missing")
+ self.assertIn(self.qtree.nw.se.rect, rects, "root.nw.se rect missing")
+
+
+ # collidepoint tests
+ @unittest.skipIf(not hasattr(QuadTreeNode, "collidepoint"), "missing collidepoints")
+ def test_collidepoint_out_of_bounds(self):
+ "if point is out of bounds, collidepoint should return None"
+ self.assertIsNone(self.qtree.collidepoint((101,101)), "point is out of bounds, should return None")
+
+ @unittest.skipIf(not hasattr(QuadTreeNode, "collidepoint"), "missing collidepoints")
+ def test_collidepoint_simple(self):
+ "if there are zero or one points, collidepoint just needs to return the node"
+ self.assertEqual(self.qtree, self.qtree.collidepoint((50,50)), "no points, expected root node")
+ self.qtree.add_point((50,50))
+ self.assertEqual(self.qtree, self.qtree.collidepoint((50,50)), "one points, expected root node")
+
+
+ @unittest.skipIf(not hasattr(QuadTreeNode, "collidepoint"), "missing collidepoints")
+ def test_collidepoint_split(self):
+ "if there is one split, collidepoint needs to return the correct quadrent"
+ self.qtree.add_point((75,75))
+ self.qtree.add_point((25,25))
+
+ self.assertEqual(self.qtree.nw, self.qtree.collidepoint((25,25)), "expected nw")
+ self.assertEqual(self.qtree.ne, self.qtree.collidepoint((75,25)), "expected ne")
+ self.assertEqual(self.qtree.sw, self.qtree.collidepoint((25,75)), "expected sw")
+ self.assertEqual(self.qtree.se, self.qtree.collidepoint((75,75)), "expected se")
+
+ @unittest.skipIf(not hasattr(QuadTreeNode, "collidepoint"), "missing collidepoints")
+ def test_collidepoint_complex(self):
+ "if there is one split, collidepoint needs to return the correct quadrent"
+ self.qtree.add_point((75,75))
+ self.qtree.add_point((10,10))
+ self.qtree.add_point((40,40))
+
+ self.assertEqual(self.qtree.ne, self.qtree.collidepoint((75,25)), "expected ne")
+ self.assertEqual(self.qtree.sw, self.qtree.collidepoint((25,75)), "expected sw")
+ self.assertEqual(self.qtree.se, self.qtree.collidepoint((75,75)), "expected se")
+
+ self.assertEqual(self.qtree.nw.nw, self.qtree.collidepoint((10,10)), "expected nw.nw")
+ self.assertEqual(self.qtree.nw.ne, self.qtree.collidepoint((40,10)), "expected nw.ne")
+ self.assertEqual(self.qtree.nw.sw, self.qtree.collidepoint((10,40)), "expected nw.sw")
+ self.assertEqual(self.qtree.nw.se, self.qtree.collidepoint((40,40)), "expected nw.se")
+
+if __name__ == "__main__":
+ unittest.main()
6 hw23/README.md
View
@@ -0,0 +1,6 @@
+Homework 24
+=====================
+Final Games Due
+---------------------
+
+Make sure your game is playable and turned in without bugs. This is a *release candidate* for your final game. Make sure to get some sleep so you can show off and check out all the games made by this class.
14 hw24/README.md
View
@@ -1,6 +1,10 @@
-Homework 24
-=====================
-Final Games Due
----------------------
+Homework 25
+================================
+Final writeup and Release Game
+--------------------------------
-Make sure your game is playable and turned in without bugs. This is a *release candidate* for your final game. Make sure to get some sleep so you can show off and check out all the games made by this class.
+Sit down with your group and write a short postmortem on your project wiki about how the project went. This should include what went right, what went wrong, and what the next step for the project would be if you continued.
+
+Then, release your game. Feel free to fix any minor bugs that you discovered on Monday in class.
+
+Finally, send us an email (cs112 at hampshire.edu) with a short evaluation of yourself and your partner. Tell us who did what, how it went, and if you'd work with them again.
10 hw25/README.md
View
@@ -1,10 +0,0 @@
-Homework 25
-================================
-Final writeup and Release Game
---------------------------------
-
-Sit down with your group and write a short postmortem on your project wiki about how the project went. This should include what went right, what went wrong, and what the next step for the project would be if you continued.
-
-Then, release your game. Feel free to fix any minor bugs that you discovered on Monday in class.
-
-Finally, send us an email (cs112 at hampshire.edu) with a short evaluation of yourself and your partner. Tell us who did what, how it went, and if you'd work with them again.
Please sign in to comment.
Something went wrong with that request. Please try again.