Design Pattern Examples
Overview of object-oriented design patterns
flyweight_exercise.py
Go to the documentation of this file.
6
7from io import StringIO
8import random
9
10from .flyweight_helpers import Helpers
11from .flyweight_classes import BigResourceManager, Flyweight_Class, Flyweight_Context
12
13
29def _Flyweight_GenerateBigResource(numImages : int, width : int, height : int) -> int:
30 numImages = 3 if numImages < 3 else numImages
31 numImages = 9 if numImages > 9 else numImages
32 width = max(3, width)
33 height = max(3, height)
34
35 image = [] # type: list[bytearray]
36 for row in range(0, height):
37 image_row = bytearray()
38 for imageIndex in range(0, numImages):
39 if row == 0 or ((row + 1) == height):
40 # top and bottom row are the same.
41 image_row.extend(bytearray("+{0}+".format('-' * (width - 2)).encode()))
42 else:
43 # All other rows are each the same.
44 c = str(imageIndex)
45 image_row.extend(bytearray("|{0}|".format(c * (width - 2)).encode()))
46 image.append(image_row)
47
48 resourceId = BigResourceManager.AddResource(image)
49 return resourceId
50
51
52
56def _Flyweight_ClearDisplay(display : list[bytearray]) -> None:
57 for row in display:
58 for index in range(0, len(row)):
59 row[index] = ord('~')
60
61
62
70def _Flyweight_GenerateDisplay(width : int, height : int) -> list[bytearray]:
71 display = []
72
73 for row in range(0, height):
74 display.append(bytearray((' ' * width).encode()))
75
77 return display
78
79
80
84def _Flyweight_ShowDisplay(display : list[bytearray]) -> None:
85 for row in display:
86 print(" {}".format(row.decode()))
87 print()
88
89
102def _Flyweight_MoveFlyweights(flyweightInstances : list[Flyweight_Class], display_width : int, display_height : int) -> None:
103 for flyweight in flyweightInstances:
104 context = flyweight.Context
105 image_width = flyweight.ImageWidth
106 image_height = flyweight.ImageHeight
107 newx = context.Position_X + context.Velocity_X
108 newy = context.Position_Y + context.Velocity_Y
109
110 if newx < 0 or (newx + image_width) > display_width:
111 # Bounce off left or right edge.
112 context.Velocity_X = -context.Velocity_X
113 if newx < 0:
114 newx = 0
115 else:
116 newx = display_width - image_width
117
118 if newy < 0 or (newy + image_height) > display_height:
119 # Bounce off top or bottom edge.
120 context.Velocity_Y = -context.Velocity_Y
121 if newy < 0:
122 newy = 0
123 else:
124 newy = display_height - image_height
125
126 context.Position_X = newx
127 context.Position_Y = newy
128 flyweight.Context = context
129
130
131
139def _Flyweight_RenderFlyweights(flyweightInstances : list[Flyweight_Class], displayArea : list[bytearray]) -> None:
140 # Render the image into the "display", one image for each instance
141 # of the Flyweight class.
142 for flyweight in flyweightInstances:
143 context = flyweight.Context
144 flyweight.Render(displayArea, context.OffsetXToImage, context.ImageWidth, context.ImageHeight, int(context.Position_X), int(context.Position_Y))
145
146
147
153def GenerateVelocity() -> float:
154 speed = ((random.random() * 5) + 1) / 5.0
155 direction = 1.0 if ((random.random() * 100) > 50) else -1.0
156 return speed * direction
157
158
159
181def _Flyweight_GenerateFlyweightClasses(bigResourceId : int, numFlyweights : int,
182 image_width : int, image_height : int, display_width : int, display_height : int) -> list[Flyweight_Class]:
183 flyweightInstances = []
184
185 # Generate the instances of the flyweight class, randomizing the position
186 # of each flyweight within the display.
187 for index in range(0, numFlyweights):
188 context = Flyweight_Context()
189 context.OffsetXToImage = index * image_width
190 context.ImageWidth = image_width
191 context.ImageHeight = image_height
192 # Make sure the entire image can be rendered at each position
193 context.Position_X = random.random() * (display_width - image_width)
194 context.Position_Y = random.random() * (display_height - image_height)
195 # Randomize the initial velocity.
196 context.Velocity_X = GenerateVelocity()
197 context.Velocity_Y = GenerateVelocity()
198
199 # Create an instance of the Flyweight_Class for the given big
200 # resource and with the new context.
201 flyweightInstances.append(BigResourceManager.CreateFlyweight(bigResourceId, context))
202 return flyweightInstances
203
204
205
222
223# ! [Using Flyweight in Python]
225 print()
226 print("Flyweight Exercise")
227
228 # Define the display and image size.
229 DISPLAY_WIDTH = 80
230 DISPLAY_HEIGHT = 20
231 IMAGE_WIDTH = 30
232 IMAGE_HEIGHT = 5
233 NUMFLYWEIGHTS = 5
234 NUM_ITERATIONS = 1000
235
236 bigResourceId = _Flyweight_GenerateBigResource(NUMFLYWEIGHTS, IMAGE_WIDTH, IMAGE_HEIGHT)
237 flyweightInstances = _Flyweight_GenerateFlyweightClasses(bigResourceId, NUMFLYWEIGHTS,
238 IMAGE_WIDTH, IMAGE_HEIGHT, DISPLAY_WIDTH, DISPLAY_HEIGHT)
239
240 # Create the "display".
241 # We use a list of character arrays so we can write to each
242 # character position individually. In C#, strings are immutable
243 # and changing a character in a string is not allowed.
244 displayArea = _Flyweight_GenerateDisplay(DISPLAY_WIDTH, DISPLAY_HEIGHT)
245
246 # Finally, display the rendered output.
247 print(" The image rendered {0} times:".format(NUMFLYWEIGHTS))
248 print() # Blank line for iteration count
249 _Flyweight_RenderFlyweights(flyweightInstances, displayArea)
250 _Flyweight_ShowDisplay(displayArea)
251
252 helpers = Helpers()
253 # Now let's have some fun and bounce those images around for a while!
254 # (Or until a keypress.)
255 cursorLeft, cursorTop = helpers.getcursorposition()
256 if cursorLeft != -1 and cursorTop != -1:
257 cursorTop -= DISPLAY_HEIGHT + 1
258
259 for index in range(0, NUM_ITERATIONS):
260 if cursorLeft != -1:
261 helpers.setcursorposition(cursorLeft, cursorTop - 1)
262 print(" {0:5}/{1} iterations [press a key to exit early]".format(index + 1, NUM_ITERATIONS))
263 if cursorLeft != -1:
264 helpers.setcursorposition(cursorLeft, cursorTop)
265
266 _Flyweight_ClearDisplay(displayArea)
267 _Flyweight_MoveFlyweights(flyweightInstances, DISPLAY_WIDTH, DISPLAY_HEIGHT)
268 _Flyweight_RenderFlyweights(flyweightInstances, displayArea)
269 _Flyweight_ShowDisplay(displayArea)
270 helpers.sleep(16) # 60 frames a second
271 if helpers.checkforkey():
272 helpers.readkey()
273 break
274
275 print(" Done.")
276# ! [Using Flyweight in Python]
Represents the context for an instance of the Flyweight_Class.
Class containing a number of helper methods for use in the Flyweight Pattern example.
def Flyweight_Exercise()
Example of using the Flyweight Pattern.
int _Flyweight_GenerateBigResource(int numImages, int width, int height)
Generate a big resource, in this case, a text master "image" of the specified height,...
None _Flyweight_RenderFlyweights(list[Flyweight_Class] flyweightInstances, list[bytearray] displayArea)
Render the image into the display, once for each flyweight instance.
None _Flyweight_MoveFlyweights(list[Flyweight_Class] flyweightInstances, int display_width, int display_height)
Move the given flyweight instances within the display, bouncing them off the edges of the display.
list[Flyweight_Class] _Flyweight_GenerateFlyweightClasses(int bigResourceId, int numFlyweights, int image_width, int image_height, int display_width, int display_height)
Helper method to generate the specified number of flyweight class instances and associate those insta...
None _Flyweight_ShowDisplay(list[bytearray] display)
Render the display to the screen.
list[bytearray] _Flyweight_GenerateDisplay(int width, int height)
Generate a display area in which to render the big resource.
float GenerateVelocity()
Generate a random velocity, which includes a speed and a direction.
None _Flyweight_ClearDisplay(list[bytearray] display)
Clear the "display" to a background image, erasing whatever was there before.