Reactors and Posns
Reactors
my-reactor =
reactor:
init: init-posn,
to-draw: crime-scene,
on-tick: solve-case,
on-key: move-glass,
stop-when: found-it
end
- The
init-posn is the posn that we want to start our magnifying glass at. Remember that we want ours to start out at a random position!
- The
to-draw function (crime-scene) should take in a posn so that it knows where to draw the magnifying glass! It should also return (output) a posn to pass along to on-tick so that we know where we last left off.
- The
on-tick function (solve-case) is run at every “time tick”, which is how Pyret measures time (think of it as every split second). solve-case takes in a posn from crime-scene so we know where the magnifying was last seen. Then, we can update that posn to keep the magnifying glass continuously moving. This updated posn is given back to to-draw so that our update is reflected in the animation.
- The
on-key function (move-glass) is called every time a key is pressed. It takes the output posn from to-draw (so that it knows where we left off) and moves it according to the key press. E.g., if the left arrow is pressed, on-key should take the magnifying glass’ posn and shift it to the left. It returns the updated posn. Again, this updated posn is given back to to-draw so that our update is reflected in the animation.
- The
stop-when function (found-it) takes in a posn and returns a boolean. If that boolean is true, it tells our reactor that our animation is over and that it should stop! If it’s false, it will continue updating posn's with on-tick and on-key and continue updating the animation with to-draw.
Posns and Datatypes
data Posn:
| posn(x :: Number, y :: Number)
end
What is a datatype? You’re already familiar with a few… int and string are examples of datatypes you’ve already used! But what if the kind of data that you’re working with in your program is not well-described by a type that Pyret has built-in for you? Let’s say that you’re building a house. Every function that helps to build the house (maybe build-foundation, lay-bricks, shingle-roof) has to know the x- and y-locations where you’d like to build something. Instead of passing the x- and y-values as separate inputs to each of these functions, you can store both locations together in a new datatype (calling it Position, or Posn for short)! Much like the way a variable of type int “knows” its value, a Posn also knows its value. BUT in this case, the value just happens to have two separate pieces of information, the x- and y-location. In this way, we see that we can simplify and module our code to use and store data effectively.
By defining a posn datatype, you are telling the program, “This is something that will appear later in my program, and I want a way to build the same thing multiple times with different characteristics.” So, when you make a posn in your program, you are building the same structure each time: a variable of type posn! The difference between the posn variables you make are the x, y values entered as parameters (inputs).
A slightly more complicated example
Let’s say you want to build a new data type that represents an animal. What kind of information do you need to know about an animal? Maybe how much it weighs, if it has hair and what color it is?
Here is how we would declare an animal data type:
data Animal:
| animal(has-hair :: Boolean, weight :: Number, color :: String)
end
To create an Animal, we would write:
poodle = animal(true, 20, "black")
And to find out if this poodle we just created has hair, we can write poodle.has-hair and the result of this line of code will be the Boolean true because our poodle, as we defined it, has hair!
Confused? Ask a TA! This is a challenging concept, and it may take a little while for this idea to sink in. Don’t worry if it doesn’t make sense yet, it will with time and practice!
Reactors and Posns
Reactors
init-posnis the posn that we want to start our magnifying glass at. Remember that we want ours to start out at a random position!to-drawfunction (crime-scene) should take in aposnso that it knows where to draw the magnifying glass! It should also return (output) aposnto pass along toon-tickso that we know where we last left off.on-tickfunction (solve-case) is run at every “time tick”, which is how Pyret measures time (think of it as every split second).solve-casetakes in aposnfromcrime-sceneso we know where the magnifying was last seen. Then, we can update thatposnto keep the magnifying glass continuously moving. This updatedposnis given back toto-drawso that our update is reflected in the animation.on-keyfunction (move-glass) is called every time a key is pressed. It takes the outputposnfromto-draw(so that it knows where we left off) and moves it according to the key press. E.g., if theleftarrow is pressed,on-keyshould take the magnifying glass’posnand shift it to the left. It returns the updatedposn. Again, this updatedposnis given back toto-drawso that our update is reflected in the animation.stop-whenfunction (found-it) takes in aposnand returns aboolean. If thatbooleanistrue, it tells our reactor that our animation is over and that it should stop! If it’sfalse, it will continue updatingposn's withon-tickandon-keyand continue updating the animation withto-draw.Posns and Datatypes
What is a datatype? You’re already familiar with a few…
intandstringare examples of datatypes you’ve already used! But what if the kind of data that you’re working with in your program is not well-described by a type that Pyret has built-in for you? Let’s say that you’re building a house. Every function that helps to build the house (maybebuild-foundation,lay-bricks,shingle-roof) has to know the x- and y-locations where you’d like to build something. Instead of passing the x- and y-values as separate inputs to each of these functions, you can store both locations together in a new datatype (calling it Position, or Posn for short)! Much like the way a variable of typeint“knows” its value, a Posn also knows its value. BUT in this case, the value just happens to have two separate pieces of information, the x- and y-location. In this way, we see that we can simplify and module our code to use and store data effectively.By defining a
posndatatype, you are telling the program, “This is something that will appear later in my program, and I want a way to build the same thing multiple times with different characteristics.” So, when you make aposnin your program, you are building the same structure each time: a variable of typeposn! The difference between theposnvariables you make are thex, yvalues entered as parameters (inputs).A slightly more complicated example
Let’s say you want to build a new data type that represents an animal. What kind of information do you need to know about an animal? Maybe how much it weighs, if it has hair and what color it is?
Here is how we would declare an animal data type:
To create an Animal, we would write:
poodle = animal(true, 20, "black")And to find out if this
poodlewe just created has hair, we can writepoodle.has-hairand the result of this line of code will be the Booleantruebecause our poodle, as we defined it, has hair!Confused? Ask a TA! This is a challenging concept, and it may take a little while for this idea to sink in. Don’t worry if it doesn’t make sense yet, it will with time and practice!