-
Notifications
You must be signed in to change notification settings - Fork 0
/
imagine-oo.py
161 lines (131 loc) · 5.04 KB
/
imagine-oo.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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# from trepan.api import debug
# import pdb
# pdb.set_trace()
import pygame as pg
import runWorld as rw
import drawWorld as dw
import image_processing as ip
import imagineFun as af
################################################################
# Initialize display
name = "Imaginator!"
width = 1200
height = 500
rw.newDisplay(width, height, name)
################################################################
# An image that we'll use when the system starts
initImage = dw.loadImage("twoeyes.bmp")
# In our initial exercise with this simulation framework, we
# represented the "game state" as a tuple. A problem with that
# approach is that it doesn't give us good names for the fields
# of the tuples (records), so we end up with lots of cryptically
# subscripted tuple values, make it hard to write, reason about,
# debug, and enhance the code. We could of course write our own
# nicely named projection functions, and that would help. This
# is what we did in Idris, where we wrote functions such as
# first (fst) and second (snd) to extract fields from tuples.
# We then saw that the *record* construct enabled us to define
# tuple types with *named* fields. The compiler then provided
# projection functions with the names of the fields, making it
# much easier to write code where the intended interpretation
# is clarified by the use of meaningful field names.
#
# We now take one step on a path to fixing the same problem in
# Python. The idea we introduce now is to use a dictionary to
# represent a tuple with named fields. To access a field, we just
# do a lookup in the dictionary.
# To illustrate this idea, we define the initial state of our
# image processing system, implicitly defining the tuple type
# that will represent the state of our application. Here are the
# fields and their meanings:
#
# runDone -- Boolean, True if "exit" selected, ends run
# needsDisplayUpdate -- set to True when display update neede
# original -- the image that's being worked on
# processed -- a copy of original, subject to editing fuitcnons
initState = {
'runDone': False,
'needsDisplayUpdate': True,
'original': initImage,
'processed': initImage.copy()
}
class State:
runDone = False
needsDisplayUpdate = True
def setImage(img):
original = img
processed = img.copy()
s = State()
s.setImage
'''
s = State()
print(s)
'''
################################################################
# updateDisplay: state -> image (IO)
# if display update needed, render both images, otherwise "skip"
#
def updateDisplay(state):
# print("Updating display with state = ", state)
if (state['needsDisplayUpdate'] == True):
dw.erase()
dw.draw(state['original'], (0,0))
dw.draw(state['processed'], (((state['original']).get_size())[0],0))
dw.flush()
state['needsDisplayUpdate'] = False
################################################################
# updateState: state -> state
# "no-op" in this application (this is not a simulation)
# i.e., this is just identity function on state type
#
def updateState(state):
return state
################################################################
# endState: state -> bool
# return True to quit pygame if runDone has been set to True
#
def endState(state):
return state['runDone']
################################################################
# handleMouseDown: state -> event -> state
# Just a stub to illustrate possibility of handling mouse events
#
#
def handleMouseDown(state, pos, button):
return(state)
# handleKeyDown: state -> state
# run command designated by user or "badChoice" if no such command
#
def handleKeyDown(state, unicode, key, mod):
print("Key pressed: ", key)
# note that Python dictionary supports "get" command. It's a
# lookup with an optional second argument that specifies what
# the result of the lookup should be if the key is not present
# in the dictionary. So the following command gets the function
# designated by the given character, or "badChoice" if there
# isn't one.
#
funcToRun = af.menu.get(key, af.badChoice)
# Run the selected function!
#
# Quiz: Why do we not have to write: state = funcToRun(state)?
#
funcToRun(state)
return(state)
################################################################
# Refresh screen at intended 20FPS
frameRate = 20
# Run the main event loop. Note that there is a change in
# the way you call runWorld: Instead of passing a single
# handleEvent function, you pass individual functions for
# handling different kinds of events; and if there is no
# need to handle particular kinds of events, you can just
# pass "None." The runWorld function makes sure that it
# does not try to call an event handler that is None.
#
# Make sure you see that we're passing initState off to
# runWorld, and that you understand that that is the state
# value that runWorld will pass back to the functions you
# define in this file.
#
rw.runWorld(initState, updateState, updateDisplay, endState, frameRate, handleMouseDown, None, handleKeyDown, None, None)