Thursday, February 15, 2024

Reaping the benefits of automated integration testing in game development

This academic year, I am working on a research and development project: a game to teach middle-school and early high-school youth about paths to STEM careers. I have a small team, and we are funded by the Indiana Space Grant Consortium. It's been a rewarding project that I hope to write more about later.

In the game, the player goes through four years of high school, interacting with a small cast of characters. We are designing narrative events based on real and fictional stories around how people get interested in STEM. Here is an example of how the project looked this morning:

This vignette is defined by a script that encodes all of the text, the options the player has, the options' effects, and whether the encounter is specific to a character, location, and year. 

We settled on the overall look and feel several months ago, and in that discussion, we recognized that there was a danger in the design: if the number of lines of text in the options buttons (in the lower right) was too high, the UI would break down. That is, we needed to be sure that none of the stories ever had so many options, or too much text, that the buttons wouldn't fit in their allocated space.

The team already had integration tests configured to ensure that the scripts were formatted correctly. For example, our game engine expects narrative elements to be either strings or arrays of strings, so we have a test that ensures this is the case. The tests are run as pre-commit hooks as well as on the CI server before a build. My original suggestion was to develop a heuristic that would tell us if the text was likely too long, but my student research assistant took a different tack: he used our unit testing framework's ability to test the actual in-game layout to ensure that no story's text would overrun our allocated space.

In yesterday's meeting, the team's art specialist pointed out that the bottom-left corner of the UI would look better if the inner blue panel were rounded. She mentioned that doing so would also require moving the player stats panel up and over a little so that it didn't poke the rounded corner. I knew how to do this, so I worked on it this morning. It's a small and worthwhile improvement: a cleaner UI with just a little bit of configuration. 

I ran the game locally to make sure it looked right, and it did. Satisfied with my contribution, I typed up my commit message and then was surprised to see the tests fail. How could that be, when I had not changed any logic of the program? Looking at the output, I saw that it was the line-length integration test that had failed, specifically on the "skip math" story. I loaded that one up to take a look. Sure enough, the 10-pixel change in the stat block's position had changed the line-wrapping in this one particular story. Here's how it looked:


Notice how the stat block is no longer formatted correctly: it has been stretched vertically because the white buttons next to it have exceeded their allocated space. 

This is an unmitigated win for automated testing. Who knows if or when we would have found this defect by manual testing? We have a major event coming up on Monday where we will be demonstrating the game, and it would have been embarrassing to have this come up then. Not only does this show the benefit of automated testing, it also is a humbling story of how my heuristic approach likely would not have caught this error, but the student's more rigorous approach did.

I tweaked the "skip math" story text, and you can see the result below. This particular story can come from any character in any location, and so this time, it's Steven in the cafeteria instead of Hilda in the classroom.

We will be formally launching the project before the end of the semester. It will be free, open source, and playable in the browser.

Friday, February 9, 2024

Tales of Preproduction: Refining the prototyping procedure

I am teaching the Game Preproduction class for the second time this semester, and this time I am joined by Antonio Sanders as a team-teacher from the School of Art. There are already a lot of interesting things happening as we have a class that is now have Computer Science majors and half Animation majors. We have also extended the class time to a "studio" duration, so we meet twice a week for three hours per meeting instead of the 75 minutes I had with my inaugural group last year.

Given that quick summary of our context, I want to share a significant change that we made to the prototyping process from last year. Last year, the team adjusted the schedule because we didn't dedicate enough ideation time to prototyping, and so this year, we set aside five days for this. Each day, the students are supposed to bring in a prototype that answers a design question. I remember this also being challenging last year, and it wasn't until late in that process that we remembered the seven questions that Lemarchand poses about prototypes in A Playful Production Process

In an effort to get the students thinking more critically about their prototypes, we have required them to write short prototype reports that address Lemarchand's seven questions. The last of the questions, which Lemarchand himself typesets in bold to show its importance, is, "What question does this prototype answer?" What the reports help reveal, which was harder to see last year, were cases where the questions themselves were either malformed or unanswerable. That is, students are going into prototyping without a good idea of what prototyping is. Several times, I've seen students show their prototypes, and when I ask what design question they answer, the students have to look it up on their reports. This is pretty strong evidence that the questions were developed post hoc. What's most troubling is that, after having completed four of the planned five rounds, these problems are still rampant.

Early in the process, my teaching partner suggested students think about design questions in the form "Is X Y?" where X is a capability being prototyped and Y is a design goal. For example "Is holding the jump button down to fly giving the player a sense of freedom?" While this heuristic proved helpful, a lot of students struggled with it: in part, I think they didn't understand that it was only a heuristic, and in part because they haven't practiced the analysis skills required to pull a design question out of an inspiration. If I were to use this again, I'd follow the obvious-in-retrospect need to rename those variables, to something like "Does this player action produce this design goal?" (Unfortunately, the discussion of design goals comes up later in the book, so maybe even this idea is too fuzzy for the students.)

Many of the questions that students want to pursue are actually research questions. I mean this in both the colloquial and the academic senses. A question like, "Does adding a sudden sound make the player scared when they see the monster?" is obviously answered in the affirmative: one need only look at games that induce jump-scares to see that this is effective. Questions like, "Do timers increase player stress?" are simple design truisms that are not worth prototyping. In yesterday's class, I tried to explain to the students that if the question is generic then it's a research question, and that design questions are always about specifics. In particular, through science, we approach generic questions through specific experiments that attempt to answer the general question; through design, we answer specific questions through specifics directly.

Reflecting on these problems, it becomes clear that the earlier parts of the semester were not goal-directed enough. Students acknowledged after our in-class brainstorming session that they were not brainstorming game ideas (but that's a topic for another post). When the students did research, many of these were also not goal-directed. Now, in prototyping, we're more easily to see what students are interested in, and we can point out to them that their interests and issues can and should be solved by blue-sky ideation or by research. However, we haven't baked that into these first five weeks. Put another way, we took a waterfall approach to ideation whereas perhaps next year we should try an iterative one.

We're in the process of collecting summaries of all the students' prototypes. I put together a form that uses this template for students to self-describe prototypes that are viable for forming teams around:

This game will be a GENRE/TYPE where the player CORE MECHANISM to GOAL/THEME. 

I'm eager to see if this was a helpful hook for the students. I will have to ask them about it on Tuesday and then see if it's something we can use with next year's cohort.

Tuesday, January 2, 2024

Notes from "Grading for Growth"

I read portions of Grading for Growth as part of my preparations for the Spring's preproduction class. This book makes a case for "alternative grading," establishing four pillars for their efforts. These are:

  1. Clearly defined standards
  2. Helpful feedback
  3. Marks indicate progress
  4. Reattempts without penalty
I've been reading Talbert's blog for some time, and it's that last one that gives me some difficulty. I was hoping that reading the book would help me understand some practical matters such as grading management and dealing with skills that build upon each other. However, I found myself taking more notes about CS222 Advanced Programming and CS315 Game Programming than about CS390 Game Studio Preproduction.

I have read Nilson's Specification Grading and many articles on alternative grading, so I skipped through some of the content and case studies. The first case study is the one that was most relevant to me: a case of a calculus class in which the professor used standards-based grading (SBG). This was contributed by Joshua Bowman at Pepperdine University.

One of the tools that I had not fully considered before is the gateway exam. Bowman gives a ten-question exam early in the semester. Students must pass at least nine questions to pass the exam. Students get five chances to retake the exam, and a passing grade is required for a B- or better grade. This is potentially useful to deal with some of the particular problems I have faced in CS222, where students come in with high variation in understanding of programming fundamentals while also suffering from second-order ignorance. A formalized assessment could very well help with this. 

Another useful idea from the reading is the distinction between revision and new attempt. In my own teaching, I have allowed revisions, but I frequently in CS222 find myself suggesting that students begin assignments anew with new code or contexts. This was never a clear requirement but rather a strong suggestion. Separating these two ideas could increase clarity about the significance of error or misunderstanding. In particular, this could help with a particular error mode that I have seen in CS222: a student submits a source code evaluation, I critique the evaluation, and the student resubmits an evaluation that restates what I just pointed out in the critique. This masks the distinction between a student who has learned the material and one who can effectively parrot my commentary. The problem could be avoided if I required new attempts in cases where I am using my feedback to direct the student's attention to what they have missed rather than to point out small oversights.

Regular readers may recall that I experimented with specifications-based grading in my section of CS222 in Fall 2023. I only laid out cases for A, B, C, D, and F grades, similarly to how I have implemented specs grading in CS315. The reading suggested that +/- grades can also be laid out in a specification, using them for "in between" cases.

I regularly air my frustrations with the incoherent concept of "mid-semester grades," but a piece of advice from the book struck me as useful. There was a recommendation to only give A, C, or F grades at midsemester. This is probably the right level of granularity for the task. The alternative, which I also recently came across in a blog somewhere, was to have students write their own mid-semester evaluations as a reflective exercise.

Bowman and others separate their standards into core and auxiliary. This could be useful in both CS222 and CS315, where I tend to weave together content that students are required to know from the syllabus with those that I think are useful from my experience.

The authors directly address the problem that reassessments have to be meaningful. Unlimited resubmissions will inevitably lead to students' throwing mediocre attempts at the problem in hopes that it goes away. The authors suggest two techniques for ensuring assessments are meaningful. The first is to gate the possibility for reassessment behind meaningful practice, which probably works better in courses with more objective content such as mathematics courses. The other is to require a reflective cover sheet. I have required students to give memos explaining the resubmission, but I've never given them a format for what this entails. This has led to my accepting many "memos" that show little evidence of understanding, usually when my patience is exhausted. Formalizing the memo process would benefit everyone involved.

Those are all helpful ideas for this summer, when I will likely take elements of CS222 and CS315 back to the drawing board, but what about the resubmission rate issue that I was actually looking for? Well, I found quite a surprise. The authors suggest exactly what I have been doing for years: using a token-based system or throttling resubmissions. The real puzzle here then is what exactly they mean by "reattempts without penalty," since it's not what those words actually mean together. Only being able to reattempt a subset of substandard assignments is a penalty, since from a pure learning point of view, there's no essential reason to prevent it. That is, the penalty is coming from the practical matter that teachers cannot afford to teach every student as if they are their only responsibility. This finding was anticlimactic, but part of me expected that it would be what I had found. There's no silver bullet, and if I haven't seen nor invented something better in 20+ years of alternative grading experience, then it does not exist.

(It's funny to actually type out "20+ years of alternative grading experience," but it's true. It's also one of those things that's making me feel old lately.)

Monday, January 1, 2024

The Games of 2023

In 2023, I logged 408 plays of 71 different board games. I am surprised how much lower that is than the last two years, but I think it also points to playing more heavy games rather than multiple light games. My youngest son is almost nine, and he will join in any game that we invite him. Just this morning, we rung in the new year by playing Massive Darkness 2, and he did great with one of the most complicated character classes. We can probably unload some of the kids old games and to make room for... well, honestly, the games we already have that just don't have a home on a shelf.

Here are the games that I played at least ten times this past year:

  • Frosthaven (54)
  • Clank! Catacombs (32)
  • Railroad Ink (26)
  • Everdell (19)
  • Res Arcana (16)
  • Terraforming Mars: Ares Expedition (16)
  • Oathsworn: Into the Deepwood (12)
  • Cribbage (11)
  • So Clover! (11)
  • Ark Nova (10)
  • Thunderstone Quest (10)
We haven't had Frosthaven to the table in months, so it was a shock for me to see it so strongly in the top. My son and I have played through practically all the main storyline, though we have not unlocked all the characters. I am a little disappointed that, after the main quests are done, there's not much pull to go back into the game. It's not like the game mechanisms changed much, but once there's no narrative hook to move forward, it just stopped feeling like it mattered if we collected the materials to build the buildings to get more materials to save a settlement that was actually fine.

Cribbage is a game I played a lot as a kid and watched my parents play with their friends. It's a comforting game. A glass of wine and a game with my wife always makes for a good evening.

I did not think we played Ark Nova as much last year as we did. Maybe that expansion is in our future.

As of the start of the year, my game h-index is 33, meaning that there are 33 games that I have played at least 33 times. This will certainly go up this year, as it seems I only need one more play of Castles of Mad King Ludwig to increase to 34, and that's a game I love to play. My player h-index is 19, meaning that there are 19 players with whom I have played at least 19 games. This one seems much harder to increase! 

I'll conclude by sharing the most-played games in my collection, continuing a tradition for this blog series.
  • Race for the Galaxy (112)
  • Clank (102)
  • Thunderstone Quest (102)
  • Crokinole (88)
  • Kingdomino (82)
  • My City (67)
  • Gloomhaven (66)
  • The Quacks of Quedlinburg (65)
  • Arcadia Quest (61)
  • Frosthaven (61)
  • Carcassonne (60)
  • Animal Upon Animal (56)
  • Quiddler (56)
  • Camel Up (51)
  • Terraforming Mars: Ares Expedition (47)
  • Rhino Hero: Super Battle (43)
  • Cribbage (41)
  • The Crew (40)
  • Just One (40)
  • Mage Knight Board Game (40)
  • Runebound Third Edition (40)
It may look like Race wins, but if we tally together Clank, Clank Legacy, and Clank Catacombs, the Clank family dominates with 158 total plays (102+17+39, respectively).

Thanks for reading. Happy New Year and Happy Gaming!

Wednesday, December 20, 2023

Reflecting on CS222 Advanced Programming, Fall 2023 Edition

As you may have noticed, I tried something a little different this year and extracted topical reflections into their own posts [1,2] rather than embed them into a lengthier reflection about a class. Aside from those concerns already expressed, CS222 went quite smoothly this semester. I had a small section, and I feel like I had a good rapport with the students. 

I had most recently been teaching the course on a MWF schedule, but this semester it was back to my preferred Tuesday-Thursday schedule. This means more time in one session to dive into a topic, but it also meant I touched on fewer topics. This is a worthwhile exchange, but I didn't get to all the extras I like to cover during the semester. For example, we didn't get a chance to explore state management in Flutter as much as I would have liked. That particular context is where we get into the Observer design pattern, which this batch of students will not know by name. I also did not get a chance to talk at all about software licensing and intellectual property aside from a quick, hand-waving statement that the students own the rights to their projects.

I also added a fourth week to the pre-project portion of the class, cutting a week off of the final project to compensate. This gave more time in the early part of the semester, where students tend to struggle with the basics. Shortening the iteration lengths for the final project did have the anticipated positive effect that students worked more consistently. That is, reducing the time between deliverables gave students fewer opportunities to procrastinate.

The most surprising finding this semester was that the first Clean Code assignment was too easy. I've been giving this assignment for years: read the first chapter of Clean Code and write a paragraph reflecting on which definition of "clean code" most resonates with you. It is intended as a warm-up exercise to get students used to the unconventional method of documenting and submitting work for the course. One of my students pointed out that it gave him a false sense of what to expect from assignments, all of which take orders of magnitude more effort than this first one. I am thinking of simply dropping the assignment in favor of more meaningful ones.

I teach CS222 almost every semester, but I have a break next semester while I work on a funded research project. It will be good to have a little break from it, and I imagine I will be back on rotation some time next academic year. We also had a new faculty member teach the course this Fall, but I haven't made the opportunity to talk to him about the experience yet. I will do that in Spring.

Tuesday, December 19, 2023

On the ethics of obscurity

Years ago, I experimented with what is now called "specifications grading" in CS222. I set up a table that explained to a student how their performance in each category would affect their final grade. These are not weighted averages of columns but declarations of minima. For example, to get an A may require earning at least a B in all assignments, an A on the final project, and a passing grade on the exam. This gave a clarity to the students that was lacking when using more traditional weighted averages. While publishing weighted average formulae for students technically makes it possible for them to compute their grade for themselves, in practice, I have rarely or never found a student willing to do that level of work. Hence, weighted averages, even public ones, leave grades obscure to the students, whereas specification tables make grades obvious.

What my experiment found was specifications grading made students work less than weighted averages. The simple reason for this is that if a student sees that their work in one category has capped their final grade, they have no material nor extrinsic (that is, grade-related) reason to work in other columns. Using the example above, if a student earns a C on an assignment and can no longer earn an A in the class, they see that they may as well just get a B in the final project, too, since an A would not affect their final grade.

This semester in CS222, I decided to try specifications-based final grades again. It probably does not surprise you, dear reader, that I got the same result: students lost motivation to do their best in the final project because their poor performance on another part of the class. It's worse than that, though: the final project is completed by teams, and some team members were striving for and could still earn top marks while other team members had this door closed to them. That's a bad situation, and I am grateful for the students who candidly shared the frustration this caused them.

The fact is that students can and do get themselves into this situation with weighted averages as well. A student's performance in individual assignments may have doomed them to a low grade in the class despite their performance on the final project, for example. However, as I already pointed out, this is obscured to them because of their unwillingness to do the math. What this means—and I have seen it countless times—is that students will continue to work on what they have in front of them in futile hope that it will earn them a better grade in the course.

And that's a good thing.

The student's ends may be unattainable, but the means will still produce learning. That is, the student will be engaged in the actual important part of the class. 

Good teaching is about encouraging students to learn. That is why one might have readings, assignments, projects, quizzes, and community partners: these things help engage students in processes that result in learning. It is a poor teacher whose goal is to help students get grades rather than to help them learn. Indeed, every teacher who has endeavored to understand the science of learning at all knows that extrinsic rewards destroy intrinsic motivation. 

What are the ethical considerations of choosing between a clear grading policy that yields less student learning and an obscure one that yields more? It seems to me that if learning is the goal, then there is no choice here at all. How far can one take this—how much of grading can we remove without damaging the necessary feedback loops? This is the essential question pursued by the ungrading movement, which I need to explore more thoroughly. 

I also wonder, why exactly haven't we professors banded together and refused to participate in grading systems that destroy intrinsic motivation? 

The Conflict of Individual Mastery Learning and Team Projects

I am uncertain how to optimally balance the desires for mastery learning and teamwork. This is not a new problem, but a conversation with a friend this week helped me articulate the particular pressures. I hope that summarizing the problem here will both give me practice explaining the tensions and foster conversation toward solutions.

Mastery Learning has students do work until it is done correctly. In theory, this is one the simplest and best ways to ensure that students gain the benefit we intend from assigned work. I have used a form of mastery learning for years in CS222. Students can resubmit assignments all the way through the end of the semester in order to show that they have learned from them. From very early in my experiments with mastery learning, I imposed a throttle on how many resubmissions students can use per week. This serves two purposes: it prevents students from dumping piles of work on me all at once, and because it reduces the number of evaluations I have to do at any time, it minimizes the time it takes me to give feedback to the students. I have a hard time imagining how advocates of "pure mastery learning," with any number of resubmissions allowed at any time, manage this.

I am an advocate of teamwork in undergraduate education with an important caveat that teams should only be given work that requires a team to accomplish. That is, if the work can be done by one person, it will be done by one person. There is a challenge here, where teams may not recognize how much work is actually required. That is why learning how to set scope and communicate is an implicit learning objective in almost every course I teach. I expect there to be some struggles here, the kind necessary for learning.

Mastery learning and teamwork come into conflict in my classes. Ideally, students should learn the skills and dispositions required before joining a team and working on a project together. The best way to ensure that all students learn that material is mastery learning, but with mastery learning, I cannot know when students will have completed all the work. One option is to impose an additional deadline before the project, but this seems counter to mastery learning: what would a student do after that deadline who has not mastered the requisite material? Another option is to gate the final project behind completion of the requisite material, but then teams would form in a staggered way. It is hard enough to get teams to form that can schedule sufficient out-of-class meetings to succeed, and adding any more impediments to this seems troublesome at best. An alternative way around this is to convert all the courses into studio courses, where there is no excuse for not being able to schedule time because it's built into the schedule. That comes with a significant cost to me: as much as I love studio classes, one has to recognize that they take twice as much of my time without a commensurate release of responsibilities elsewhere.

I am not sure whether traditional assignments or portfolios make a big difference in terms of this conundrum. For example, I could have students get into team projects right away, and by the end of the semester, turn in a portfolio that demonstrates their having individually met the learning objectives. This runs into the same problem as traditional resubmission of assignments, that students could put off working on the portfolios until much later than when that knowledge would have been helpful on the team projects.

The options I have sorted out seem to be the following.

  • Allow students to join team projects before they have shown mastery of the requisite material, continuing to allow resubmission of individual work while projects are ongoing.
  • Allow mastery learning resubmissions up until team projects start, or some other deadline before the end of the semester. A student's grade on those individual elements would be fixed at this point similarly to how they are at the end of a semester.
  • Gate team projects behind completion of mastery learning exercises: students can only join a team once they have shown that they have individually learned what they need to know. 
  • Separate the courses entirely: require a particular grade in a course that is all about prerequisite knowledge in order to get into a course where teams apply and build on that knowledge together.
Now that I write out that last one, it makes me realize I don't have a good answer as to why the deadline for mastery learning assignments is the end of the semester. That seems to be the tail wagging the dog. Isn't the end of the semester also an entirely arbitrary deadline? Perhaps that gives some credence to the second bullet above that I had not given it before.

I fear I'm looking for a silver bullet. In the absence of such a thing, I am curious how other faculty balance these issues.