-
Notifications
You must be signed in to change notification settings - Fork 0
/
control.py
98 lines (75 loc) · 3.23 KB
/
control.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import bisect
import pygame
import pygame.gfxdraw
import random
import sys
import optimiser
import view
import image_model
# could try optimising rendering by caching intermediate results:
# where there are repetitions of the same polygon sub-sequence (in rendering order)
# the result of rendering these independently of the rest of the sequence in any
# given rendering could then be applied to the result of head, and followed
# by the tail.
# this may not work though: I don't think alpha-blending is associative. It may
# still be possible to determine a way to refactor the mathematical expression to
# allow sub-sequences to be prerendered.
# Return ImageModel rendered onto pygame.Surface
def render( imageModel ):
# target surface
s = pygame.Surface( imageModel.size(), pygame.SRCALPHA | pygame.HWSURFACE, 32 )
s.fill( 0x00000000 )
s.fill( 0xFFFFFFFF )
for shape in imageModel.shapes():
# draw shape
# use gfxdraw because draw.polygon doesn't support alpha-blending and the
# alternative is dog-slow.
pygame.gfxdraw.aapolygon( s, shape["points"], shape["colour"]);
pygame.gfxdraw.filled_polygon(s, shape["points"], shape["colour"]);
return s
class Control():
def __init__( self ):
self.genepoolSize_ = 10
def run( self, targetImagePath ):
# enable alpha-blending
# uses display format for fast blitting
self.targetSurface_ = pygame.image.load( targetImagePath )
self.targetSurface_ = self.targetSurface_.convert( 32, pygame.SRCALPHA | pygame.HWSURFACE )
self.width_ = self.targetSurface_.get_width()
self.height_ = self.targetSurface_.get_height()
self.mainView_ = view.View( self.width_, self.height_ )
self.models_ = [self.makeRandomModel() for i in range( self.genepoolSize_ )]
self.update_model()
# for i in range(0, 2):
while True:
for event in pygame.event.get():
self._on_event( event )
def _on_event( self, event ):
"""Handle a pygame event"""
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
self._on_keydown( event )
def _on_keydown( self, event ):
"""Handle a pygame keydown event"""
if event.key == pygame.K_RETURN:
self.update_model()
def draw_model( self, m ):
self.mainView_.draw( m )
def update_model( self ):
renderedModels = [(m, render(m)) for m in self.models_]
self.evolve( renderedModels )
# TODO: render doesn't belong here; rendering should be done by something
# that avoids re-rendering, perhaps a wrapper around the model?
# should be the same object as a population, since models have to be
# rendered for fitness calculation there anyway
self.draw_model( render( self.models_[0] ))
def evolve( self, renderedModels ):
"""renderedModels: [(fitness, surface, model)]"""
self.models_ = optimiser.optimise( self.targetSurface_, renderedModels )
def makeRandomModel( self ):
m = image_model.ImageModel( self.size() )
m.randomise()
return m
def size( self ):
return (self.width_, self.height_)