Reactive🔗

    1 What is This Assignment’s Purpose?

    2 Theme Song

    3 Starter

    4 Assignment

    5 Alternative: Sprites

1 What is This Assignment’s Purpose?🔗

We want you to get practice with writing reactive programs. We expose you to a relatively simple reactive programming interface, but using a style (based on functional programming) that is quite similar to that advocated in modern programming frameworks like Reactbut in a much less complex setting.

We also want you to have some fun!

2 Theme Song🔗

Among Us Drip Theme Song Original (Among Us Trap Remix / Amogus Meme Music) by leonz

3 Starter🔗

There is no starter file! Use CPO in all its barren but fertile glory.

4 Assignment🔗

In this course, all the other assignments have well-defined end-points. This one doesn’t.

You have seen the Pyret reactive programming framework (using reactors) in class. Below we provide another: Alternative: Sprites. You can use either one for your program.

Your task is to write a program that you find interesting. You can take inspiration from anything: video games, physics simulations, modeling biological phenomena, social networks, cruise controllers, traffic simulations, psychology experiments, 2048, Wordle, Wordle bots, or whatever else strikes your fancy.

In pursuit of (usually visual) output, though, you shouldn’t sacrifice code quality. We will expect to see that you have written quality code following the guidelines established in this course, which includes testing your functions as well as your reactors! (That should include testing the reactor state after events like keypresses.)

Especially when writing games, it’s easy to get caught up in piling on complexity. No matter what causes this, remember to step back and refactor your code to be clean. Write the kind of code that you would want to review! If you need motivation, keep in mind that we won’t just be awed by the coolness of your output: the harder you make it for us to review your code, the poorer your grade will be.

Have fun. And tell us what’s neat about it.

5 Alternative: Sprites🔗

This part is entirely experimental. There is no documentation beyond what we provide below, though you are welcome to read the source.

In reactors, you have a single value that records the entire state of the program. Every handler function consumes it and produces a possibly updated version of it.

While in principle this is sufficient, in practice, for some programs, it can be a nuisance. If the reactive program has lots of little entities that each have their own local state, it’s annoying to “find” it in the single state value and even more so to re-assemble that entire state to update it. The same can be true when drawing an entity.

Therefore, we have created an alternate reactive programming library based on sprites.The sprite library was created in collaboration with Artem Agvanian. Sprites are individual entities that have their own local notion of state, display, and so on. Underneath, our sprite library merely stitches together the state of each individual sprite into a larger data structure, so it’s still built atop reactors. But it gives you a more comfortable programming interface for programs that would benefit from that kind of localization.

You are welcome to use the sprite library instead, if your design would better fit this structure.

You access the sprite library as follows:

include shared-gdrive("sprite-lib", "1oXiADjdC5WMA_iljrNdg7Dvo2mJC73_N")

(If you’re really curious, you can see the entire implementation of the sprite library over here.) The library provides you with:
  • mk-sprite, a constructor for a single Sprite (see details below) that adds the sprite to the current list of sprites

  • go-sprites :: Number, Number, Number -> List<Sprite>, which takes a width, height, and inverse-frequency of updates, and begins animating the sprites

  • reset-sprites :: -> Nothing, which resets the list of sprites to forget all previously-defined sprites

  • posn, a two-dimensional point of type Posn

  • make-sprites-reactor :: Number, Number, Number -> Reactor<List<Sprites>>, which consumes a width, height, and the inverse-frequency of updates, and returns a reactor of the sprites—this is useful for testing the sprite ensemble!

  • find-sprite-named :: String, List<Sprite> -> Sprite, which finds other sprites—useful for reading their properties in case of, e.g., a collision

We construct each sprite using mk-sprite. Each sprite has its own local state, which we will denote below as T. In addition, the World state is the state of all of the sprites combined: List<Sprite>. The mk-sprite constructor takes a collection of 2-tuples where the first element is a string and the second a corresponding value. These are the recognized constructor parameters:

Name

 

Purpose

 

Value Type

"name"

 

a name to use for finding

 

String

"init"

 

initial state

 

T

"new-state"

 

state update function

 

T, World -> T

"loc"

 

initial location

 

Posn

"new-loc"

 

location update function

 

T, Posn, World -> Posn

"rot"

 

initial rotation

 

Number

"new-rot"

 

rotation update function

 

T, Posn, Number, World -> Number

"image"

 

image to draw

 

Image

"to-draw"

 

drawing function

 

T, World -> Image

"collision-threshold"

 

distance for collision

 

Number

"on-collision"

 

collision handling function

 

Sprite, Sprite, World -> Sprite

"on-key"

 

key handler

 

String, Sprite, World -> Sprite

The key thing is that every one of these parameters is optional. The simplest sprite program you can create and run is

include reactors

include shared-gdrive("sprite-lib", "1oXiADjdC5WMA_iljrNdg7Dvo2mJC73_N")

 

[mk-sprite:]

go-sprites(500, 500, 0.025)

We encourage you to play around with these options and see how they impact the sprites!

Every Sprite also has a get and update method. The get method takes a key, which is one of the strings in the leftmost column above, and returns a value of the rightmost column’s type. The update method takes a key (again, one of the above strings) and a value of that key’s type, and returns an updated Sprite.

If you want a few illustrative examples of the Sprites library, see this file. This defines a collection of demo functions: d0, d1, and so on. Each takes no arguments, so run it, e.g., d0(). Read the comments above each that tell you what each demo does.