Sea Monsters is a class taught by Pete Girguis that, you guessed it, covers Sea Monsters. From the description:
During this course we explore sea monsters through a social, spiritual, literary, and scientific lens. We study the sea monsters that flourish on ancient maps to understand the minds of sixteenth century scholars. We examine the bodies of real sea monsters, and consider the world in which such grotesque creatures might evolve. We read tales of creatures from classic and contemporary literature. Most importantly, we develop a better understanding of how humans perceive the world, and how our consciousness can simultaneously embrace our wildest dreams and cower from our greatest fears. Sea monsters, both real and imagined, tell us much about life in the deep sea, and even more about humankind.
Pete has offered this course as both a freshman seminar course and an extension school course in the past, and in Spring 2020 (yes, that spring), I was one of his TFs (teaching fellow) for the extension school course. The very first assignment students receive, due the second class, is a drawing of their own personal sea monster. They ranged from Jörmungandr-style goliaths and Creature from the Black Lagoon, to black abysses of nothingness and my own: swarms of sea flees. I loved this.
And for the first midterm exam, Pete gives students a creative writing assignment:
Imagine you are a cultural anthropologist. You are visiting Mars, and you discover a pile of books from an ancient alien race. These books are entirely about their sea monsters (real or imaginary, your choice!). 1) Describe, in detail, two different "sea monsters" on this alien world. 2) As an anthroplogist, tell us what the description of these "sea monsters" say to you about this society (violence, culture, etc). Which I also loved.
One day when we were reviewing the class and the midterms, I thought it would be a pretty fun idea to create 'book-end' assignments. Since the students draw their own monsters for the second class, what if for their last assignment, having spent the semester learning about mythologies and portrayals, they created a mythology of some sort (origin story, campfire horror story, bedtime fable) for the monster they had created.
This Sea Monsters website is meant to be a showcase of that book-end assignment.
Students' creations would be displayed in a gallery and when an image is clicked, a modal pops up and displays the mythology.
I started with this demo gallery and went from there, deleting the on-click zoom and replacing it with the bootstrap modal component. Nothing super fancy or difficult to me now, but it was my first time really doing any of this at the time and I remember finding it nontrivial.
The next page is the memory game. Marlon, head of the Bok Learning Lab, recommended I build this as a way to learn React state and effects, and he was right! I set up three levels of game: Easy (6x2 grid), Medium (6x3 grid), and Hard (6x4). The cards are randomly drawn for the firebase data, doubled, and then randomly shuffled again to mix up the deck before 'drawing the board.'
And it's not a real game unless there's a scoring mechanism. I set the default score to 100 and then subtract from that the total clicks minus how many clicks it would take to win if the user played a perfect game. I thought about including a time element but thought that would be too evil. Calculating score just based on extra clicks is already brutal enough, haha.
In our coding group at the Bok, we learned about curried functions. In brief, a normal function takes input parameters if necessary and then generates the output promptly.
function Example(x){
*does something to x*
return x'
}
However, what if you have a function that takes two inputs, and you receive those two inputs at different times?
function ExampleAdd(x, y){
return x+y
}
You can either store the first input somewhere and grab it when you have the second input and run the function then, or you can curry the function. That is, when you have the first input, define a new function equal to the actual function with the first parameter, and the new function accepts the second input as the only input. When the curried function is run, it works like the first function using both input parameters together.
function CurryExampleAdd(x){
return function (y){
return x+y
}
}
To use this, I would say let dummyCurry = CurryExampleAdd(2). As you can see above, the nested functions means that when I call CurryExampleAdd, I get another function as the return, and I have to define that function as a variable (dummyCurry) in order to call it when I know the second parameter: let result = dummyCurry(3), and then finally the function will finish running and the result should be 5.
There are a lot of instances or reasons where you might choose to curry, and my use-case was checking for matches when the cards in my memory game were clicked. When the first card is clicked, I give the id to the matching function, curriedCheckMatch and define the returned inner function as f. And when the second card is clicked, I give the id to the curried matching function, f, and then the matching function either flips the cards back upside-down (they weren't a match), or updates the array that keeps track of which cards are matched and allows the user to click another card.
I wanted to explain this mostly because I was super proud of myself at the time (and still am) for understanding curried functions and useState well enough to even include it. It's not super complex from what I've seen of other curried functions, but still. Go me!
This project is 'finished' in that I'm no longer working on it and it does what it is supposed to do, but there are definitely things I'd like to go back and improve, change, and add when I have the time. The first is, make it responsive. This was my first website and I still barely understood what responsive meant, let alone all the design elements and tweaks that go into making a responsive website. The gallery is the only bit that works responsively, unfortunately. Not the modals, though. Second, I would like to vastly improve the scoring mechanism. Ideally, there would be a 'loading' page where users input a username and then all their scores from a local session would be stored and written to firebase. I could write a 'Top 10 Scores' component that displays the username, difficulty level, and score and users would be able to play against each other asynchronously. Maybe even some fun visualizations that people could play with, too? I feel like that would be really cool.
This fall students submitted their mythologies along with their drawings and per usual, they did not submit an unformatted paragraph as expected. So I remade the entire website using Next.js, Contentful, and Vercel in order to accommodate formatted text, and that is the link in the header.