Hi,<br><br>I've added a few new examples to Pippy. They're available in my repository (<a href="http://git.sugarlabs.org/projects/pippy/repos/dgaletic-gsoc2010">http://git.sugarlabs.org/projects/pippy/repos/dgaletic-gsoc2010</a>); I haven't made an .xo since I'm having some problems with my Sugar installation.<br>
<br>Since this is about learning Python, in each of them I've tried to have several places where the learner is invited to modify come code.<br><br>This one draws the Koch snowflake using pygame. The user can decrease/increase the number of triangles with left and right arrows.<br>
<br>diff --git a/data/GSOC examples/Koch snowflake b/data/GSOC examples/Koch snowfla<br>new file mode 100644<br>index 0000000..2fb218e<br>--- /dev/null<br>+++ b/data/GSOC examples/Koch snowflake <br>@@ -0,0 +1,208 @@<br>
+# This example draws a shape called the Koch snowflake. <br>
+<br>+import pippy, pygame, sys<br>+from pygame.locals import *<br>+from random import *<br>+import math<br>+<br>+# always need to init first thing<br>+pygame.init()<br>+<br>+# XO screen is 1200x900<br>+size = width, height = 1200, 900<br>
+<br>+# create the window and keep track of the surface<br>+# for drawing into<br>+screen = pygame.display.set_mode(size)<br>+<br>+# turn off the cursor<br>+pygame.mouse.set_visible(False)<br>+<br>+<br>+# Set some variables.<br>
+# Snowflakes are white!<br>+color = (255,255,255)<br>+<br>+# the center point of the screen<br>+# We need it because we'll place out triangle around it.<br>+center = width / 2, height / 2<br>+<br>+# Side of an equilateral triangle (the one we start with).<br>
+# Here it is defined relative to the resolution of the screen.<br>+# Practice: We could play with other values, absolute (like a = 100) or <br>+# relative (a = height / 2, a = width / 3, etc). What looks best for you?<br>
+a = height/1.4 <br>+<br>+# Height of that triangle.<br>+# Just a simple geometry formula, nothing Python-special about it.<br>+h = int(a * math.sqrt(3) / 2) <br>+<br>+# These will be the vertices for the starting triangle.<br>
+# The triangle vertices are named like this:<br>+#<br>+# C<br>+# / \<br>+# A _ B<br>+#<br>+A = center[0]- a/2, center[1] + h/3<br>+B = A[0] + a, A[1]<br>+# To find the third point, we need slightly more advanced math.<br>
+# If you with to understand it, you could try finding some material about trigo<br>+# We use the coordinates of vertice A to calculate where point C will be.<br>+C = A[0] + math.cos(math.pi/3) * a, A[1] - math.sin(math.pi/3) * a<br>
+<br>+# This class will allow us to store data about a line.<br>+class Line(object):<br>+ def __init__(self, a = A, b = B):<br>+ # This is how a line object will remember its points and length.<br>+ self.A = a<br>
+ self.B = b<br>+ self.points = [self.A, self.B]<br>+<br>+ # We use the Pythagorean theorem to calculate the length of a line<br>+ # from the coordinates of its points.<br>+ self.length = math.sqrt( (a[0]-b[0])**2 + (a[1]-b[1])**2 ) <br>
+ <br>+ # Projection of the line on the x axis.<br>+ # We use it to figure out the angle which the line closes with the x ax<br>+ projection_length = b[0] - a[0]<br>+<br>+ # If the line is descending, the angle is negative. Trigonometry, again<br>
+ if b[1] > a[1]:<br>+ self.angle = -math.acos(projection_length / self.length)<br>+ else:<br>+ self.angle = math.acos(projection_length / self.length)<br>+<br>+ # To draw new shapes, an old line must be split into its thirds.<br>
+ def split(self):<br>+ third = self.length / 3.0<br>+ self.D = self.A[0] + math.cos(self.angle) * third, \<br>+ self.A[1] - math.sin(self.angle) * third<br>+ self.E = self.A[0] + math.cos(self.angle) * 2*third, \<br>
+ self.A[1] - math.sin(self.angle) * 2*third<br>+ self.points.append(self.D)<br>+ self.points.append(self.E)<br>+<br>+# Give a line (from which we'll need the coordinates of its starting point) and<br>
+# an angle, calculate the position of a new point - the vertex of out snowflake<br>+# The length of its sides should be 1/3 of the length of the line from which<br>+# it is made. <br>+def calculate_new_point(line, angle):<br>
+ p = line.D[0] + math.cos(angle + line.angle) * line.length / 3, \<br>+ line.D[1] - math.sin(angle + line.angle) * line.length / 3<br>+ return p<br>+<br>+<br>+# The following function from a single line, like this: <br>
+# <br>+# A___B<br>+# <br>+# creates four lines, like this:<br>+#<br>+# F<br>+# A_D/ \E_B<br>+#<br>+def transform_line(line):<br>+ line.split()<br>+ C = calculate_new_point(line, math.pi/3)<br>+ line1 = Line(line.A, line.D)<br>
+ line2 = Line(line.D, C)<br>+ line3 = Line(C, line.E)<br>+ line4 = Line(line.E, line. B)<br>+ lines = [line1, line2, line3, line4]<br>+ return lines<br>+<br>+# For each line in starting_lines, call transform_line().<br>
+# Repeat "depth" times for each line created this way.<br>+def produce_lines(starting_lines, depth):<br>+ all_lines = starting_lines<br>+ for i in range(depth):<br>+ new_lines = []<br>+ for line in all_lines: <br>
+ new_lines += transform_line(line)<br>+ # clearn the old lines first<br>+ all_lines = [] <br>+ all_lines = new_lines<br>+ return all_lines<br>+<br>+# Write the lines on screen.<br>+def draw_lines(lines):<br>
+ for line in lines:<br>+ pygame.draw.line(screen, color, line.A, line.B)<br>+<br>+<br>+# The color we'll use for the screen background (black).<br>+bgcolor = (0,0,0)<br>+<br>+<br>+# Lines for the initial triangle.<br>
+# Remember, the vertices are named like this:<br>+#<br>+# C<br>+# / \<br>+# A _ B<br>+#<br>+# , could be changed to:<br>+#<br>+# B<br>+# / \<br>+# A _ C<br>+#<br>+# if that felt more natural.<br>+AC = Line(A, C)<br>
+CB = Line(C, B)<br>+BA = Line(B, A) <br>+starting_lines = []<br>+starting_lines.append(AC)<br>+starting_lines.append(CB)<br>+starting_lines.append(BA)<br>+<br>+# The starting depth is 0; we just need the triangle.<br>+depth = 0<br>
+<br>+# For displaying the instructions.<br>+use = "Use left and right arrows"<br>+font_size = 36<br>+# Remember, colors are in RGB (Red, Green, Blue) system. <br>+font_colour = (10, 250, 20)<br>+font = pygame.font.Font(None, font_size)<br>
+text = font.render(use, True, font_colour)<br>+text_box = text.get_rect()<br>+# Where the box will be placed.<br>+text_box.top = 100<br>+text_box.left = 50<br>+<br>+lines = starting_lines<br>+<br>+while pippy.pygame.next_frame():<br>
+ for event in pygame.event.get():<br>+ if event.type == QUIT:<br>+ sys.exit()<br>+ # When R arrow is pressed, go one step further.<br>+ # This means creating new lines on each existing line.<br>
+ elif event.type == KEYDOWN and event.key == K_RIGHT and depth < 6:<br>+ lines = produce_lines(lines, 1)<br>+ depth = depth +1<br>+ # When L arrow is pressed, go one step back, reducing the complexity of<br>
+ # the snowflake.<br>+ # Basically, goes depth-1 steps forward from the starting lines.<br>+ elif event.type == KEYDOWN and event.key == K_LEFT and depth > 0:<br>+ depth = depth-1<br>+ lines = produce_lines(starting_lines, depth)<br>
+ elif event.type == KEYDOWN:<br>+ sys.exit() <br>+ screen.fill(bgcolor)<br>+ # Display the current step.<br>+ msg = "Step: " + str(depth) + "/6"<br>+ text2 = font.render(msg , True, font_colour)<br>
+ text_box2 = text2.get_rect()<br>+ text_box2.top = 130<br>+ text_box2.left = 50<br>+ # Write the instructions and the current step on the screen.<br>+ screen.blit(text, text_box)<br>+ screen.blit(text2, text_box2)<br>
+ # Draw the lines on the screen.<br>+ draw_lines(lines)<br>+ # Refresh the screen.<br>+ pygame.display.flip()<br>+<br><br>