In part 1 of my Christmas themed React series, I got to the point where people could be added to our list of participants. The goal for this post is to assign recipients to each person and display that information to the user. The algorithm we’ll employ will be nothing fancy and in a future post I might look to improve upon it. It probably won’t matter much the real-world use because most people won’t have thousands of participants but it’s an opportunity to learn and I wouldn’t want to waste it. For now, let’s just get it working.

First, a public service announcement: Install the React Chrome Developer Tools. It’ll make life much easier. The More You Know™.

I’ll begin by adding the button the user clicks first. We won’t need any kind of function or class for a component here and it’ll go in our render function below our lists.

The button will have an onClick handler, notice the use of camelCase.  As I did for the form submit handler, we’ll need to bind the context to it, which I’ll put in the constructor.

We’ll also add the function to our class and, for now, have it update our state to set assignments to just be a copy of participants.

Try it out and you should see our shiny new button. Add some participants. Press the shiny button. Our app should update and show two lists which are identical.

PSA #2: When setting state, you don’t have to redeclare every property of the state. Objects passed into state are merged with the previous state. The power is yours!™

What we really want to happen is to set assignments to an array of shuffled people, where index i in the participants array doesn’t equal the same person in the assignments array. In other words, a person shouldn’t be their own secret santa. There’s a few ways to handle this.

  • Brute force. We could just shuffle the array and then check to make sure nobody is assigned to themselves. If they are, then we shuffle again. Lather, rinse, repeat. It’s not elegant but the more people there are the less likely you are to be assigned to yourself. It could become a problem if we ever allow the user to specify people a person cannot have as an assignment, for example, Jim is married to Pam and we don’t want Jim getting Pam as a secret santa and vice versa.
  • Self-removal then randomize. This would guarantee that a person could never get themselves as a secret santa, except for the last person. But we would simply deal with that by checking if the last person is their own secret santa then swapping them with someone else’s assignment. I think it would also be able to handle the problem we talked about in the previous bullet point. On top of removing the current person we’re assigning a secret santa to, we’d also remove the people they’re disallowed from getting as well. I think we’d have to sort so that people with the most exclusions would get their assignment first but I haven’t gotten to the point of trying to implement this part.
  • Graph it. I’m not great at graphs or algorithms associated with them. It’s an area I hope to explore on my blog. The gist of going this rout is that each participant is a node and is connected to all of their allowed assignments. I’m not entirely sure about the rest though which automatically rules out this option for the time being.

I’m sure there’s more solutions, but these are the ones I thought of (sadly). If anyone’s out there, let me know how you would go about it. Would love to learn. Please speak slowly and loudly.

Here’s my code for option 2. It’s not pretty. Part of coding is getting something working and then honing and refining. I haven’t gotten to latter yet.

I broke things out into two functions. assign(participants) is the main call. This loops through a copy of our participants array and assigns someone to them. The actual assigning is done within assignRecipient(curParticipant, remainingParticipants, assignments).  Hopefully you can make sense of what’s going on in there.

  1. Check if the person is in the remainingParticipants array and remove them if they are. Set a flag to true if they are.
  2. Get a random index from the remainingParticipants array, remove them from the array, and push them onto our assignments array.
  3. If we removed them from the remainingParticipants array then put them back before returning and moving onto the next person.

Back in assign, after all assignments have been made, we just have to check if the last index in the assignments array is undefined. This means that the last person would’ve been assigned themselves but because we removed them from the remainingParticipants array prior to assigning, undefined was pushed onto the array instead. To fix this, I move the second-to-last value in the assignments array to be last, and then set the penultimate value to be the last value in the remainingParticipants array. Confusing but it works.

You should have an ugly but working barebones secret santa generator. I hope you learned something. Anything. In a future post, I’ll revisit this and style it to make it look better. I’m focusing on how React works for the moment and will be moving onto Redux.

So long 2016. Happy New Year!