Commits

Christoph Schindler committed a9a9a0e

Port to picloud

Comments (0)

Files changed (1)

picloud_mandelbrot.py

+# calculate and display a mandelbrot set ("apfelmaennchen").
+# the code might be a bit involved... this is to show off how easy it
+# is to "put calculations in the cloud" - you need an account on
+# http://picloud.com/ to run the cloud version (see comments below!)
+
+import pygame
+import itertools
+import cloud
+import time
+
+class Grid(object):
+    def __init__(self, width, height, min_x, min_y, max_x, max_y):
+        self.width = width
+        self.height = height
+        self.min_x = min_x
+        self.min_y = min_y
+        self.max_x = max_x
+        self.max_y = max_y
+
+    def convert(self, xy):
+        x, y = xy
+        cx = self.min_x + x * (self.max_x - self.min_x) / self.width
+        cy = self.min_y + y * (self.max_y - self.min_y) / self.height
+        return (cx, cy)
+
+    def iter_block(self, block):
+        min_x, min_y, max_x, max_y = block
+
+        xr = xrange(min_x, min(max_x, self.width))
+        yr = xrange(min_y, min(max_y, self.height))
+
+        return itertools.product(xr, yr)
+
+    def blocks(self, n, m):
+        stride_x = (self.width + n - 1) / n
+        stride_y = (self.height + m - 1) / m
+
+        for x in xrange(0, self.width, stride_x):
+            for y in xrange(0, self.height, stride_y):
+                yield (x, y, x+stride_x, y+stride_y)
+
+
+def make_colors():
+    colors = []
+    colors.append(pygame.Color(0, 0, 0, 100))
+    for angle in range(0, 180, 1):
+        c = pygame.Color(0, 0, 0, 100)
+        c.hsva = (angle, 100, 100-90*abs((angle-90)/90.0), 100)
+        colors.append(c)
+    return colors
+
+def mandelbrot(block):
+    def _mandel(xy):
+        x, y = grid.convert(xy)
+        a = b = 0
+        for i in range(depth):
+            a, b = a**2 - b**2 + x, 2*a*b + y
+            if a**2 + b**2 >= 4:
+                break
+        return (i+1) % depth
+
+    return (block, map(_mandel, grid.iter_block(block)))
+
+
+if __name__ == '__main__':
+    COLORS = make_colors()
+    DIMX, DIMY = 500, 500
+
+    # this statement starts the simulator - duh!
+    # use this to test your code before you blow your picloud allowance
+    # on buggy code. not that i've ever done that. *cough*
+    #cloud.start_simulator()
+    pygame.init()
+    screen = pygame.display.set_mode((DIMX, DIMY))
+
+    # this is the original mandelbrot set. runtime on my machine is around
+    # 30 seconds. rendering this in the cloud should take at least that
+    # much time - it's inefficient to offload small amounts of calculations.
+    center_x, center_y, radius, depth = -0.5, 0.0, 1.5, len(COLORS)
+
+    # somewhere deep within the fractal realms there is this beauty. takes
+    # around 250 seconds on my machine but should be considerably faster (5x)
+    # in the cloud
+    center_x, center_y, radius, depth = 0.001643721971153, 0.822467633298876, 0.00000000001, len(COLORS)*10
+
+    grid = Grid(DIMX, DIMY, center_x - radius, center_y - radius, center_x + radius, center_y + radius)
+
+    ts = time.time()
+
+    # local version
+    data = itertools.imap(mandelbrot, grid.blocks(5, 5))
+
+    # cloud version - you need an apikey from http://picloud.com/ for this
+    #data = cloud.map(mandelbrot, grid.blocks(5, 5))
+
+    for block, values in data:                 # local version
+    #for block, values in cloud.iresult(data): # cloud version
+        print '[%05.2f] new block' % (time.time() - ts)
+        for (x, y), v in zip(grid.iter_block(block), values):
+            screen.set_at((x, y), COLORS[v % len(COLORS)])
+
+        pygame.display.flip()
+
+    cloud.close()
+    print 'calculations completed in %05.2f seconds.' % (time.time() - ts)
+    while pygame.event.wait().type != pygame.QUIT:
+        pass
+