Once you have figured out how to get the master to exit cleanly, you should use the remaining time in class to begin work on Assignment 1. We recommend that you work on your implementation of Locks, the correctness criteria that you'll want to ensure with Locks, and, time permitting, a plan for building unit tests for checking those criteria.
What follows are both some guidelines and some shortcuts that you shouldn't take.
In general, the correctness of your synchronization scheme should not depend on knowing in advance how many instances of things you'll be synchronizing. For example, in whalemating, your solution should be independent of NMATING. (And in Assignment 1, your solutions should be independent of things like the number of elves or balloon ropes.)
If you cannot state clearly the correctness criteria for a synchrnoization solution, you are unlikely to be able to code it. So, think hard about what correct means. Frequently, when you do this, approaches will crystalize.
The most important thing to learn is to select the right primitive for a problem. In class we've focused on semaphores, because you don't yet have implementations for other primitives. However, once you've completed Assignment 1, you'll have several primitives from which to choose. If you pick the one best-matched to the problem, you'll find it much easier to synchronize the problem. Developing this intuitive feel for the right primitive will help throughout the rest of this semester and beyond.