MafiaTools Dev Notes

Why does this exist?

Maybe as a former CS teaching assistant, I wrote this for its possible informative value for CS students. Maybe it's documentation for the unlikely case that someone contributes to the repository. Maybe I have a grandiose notion of not wanting my work to be forgotten when I am. You decide.

Automod Dev Notes

On anonymous functions

During my term on the CS 2110 course staff, many students asked me about anonymous functions (sometimes called "lambdas") and why they're necessary. I can tell you firsthand that they're very important. Automod has hundreds of anonymous functions at this writing! To explain the purpose of anonymous functions, here's an example actually used by Automod.

/*Call f and return its return value with probability p; do nothing and return false with probability 1-p.*/
chance=(p,f)=>Math.random()<p&&f();

Aside from syntax differences between JavaScript and Java, this code does not meet 2110's style rules. Don't write code like this in assignments! Web developers often "compress" code in this fashion to reduce file size.

Anyway, this defines a function chance(p,f) with arguments p and f, a float and a function respectively. It does as the comment says. Consider a simple example function ex().

/*Log "Mafia" to the console. Return void.*/
ex=()=>{console.log("Mafia")}

These functions are in fact written in the arrow function style of anonymous functions so hopefully you understand the syntax a bit.

So what if we wanted a function that has a 5% chance to log "Mafia" in the console? We can write it in one of two ways shown below (technically, others exist). If we wanted a 5% chance, p would be .05, but I use a 100% chance below to avoid ambiguity.

chance(1,ex())
chance(1,()=>ex())

Open the browser console and try running each one.

Both of them logged "Mafia", but why did the first one throw an error? Let's see what happens when each is run.

  1. The first chance call evaluates its arguments. The first argument evaluates to 1. ex is called, which logs "Mafia" and causes the ex() argument to evaluate to its return type (void, or undefined in JavaScript). The error occurs when chance tries to call its second argument, whose value is undefined. "Calling" an undefined value as if it were a function throws an error.
  2. The second chance call evaluates its arguments. The first argument evaluates to 1. The second argument evaluates to a function object, but that function is not called immediately! Then, chance calls its second argument as a function. This time it is actually a function—no errors occur.

The case where the most students had trouble was in JUnit's assertThrows(), which asserts that a particular snippet of code throws a specified exception. Why that snippet must be given as an anonymous function is similar to the example above. assertThrows contains code to handle exceptions thrown by the snippet, so it can check if the desired exception was thrown. With an anonymous function, this is indeed what happens. assertThrows calls the anonymous function and handles any exceptions it throws. But if the snippet of code is written without an anonymous function, it is evaluated immediately, throwing an exception before assertThrows can handle it, and the test crashes.

Incidentally, Automod's anonymous functions are mostly used to wake up specific players at later times by putting them in a queue so players wake up one at a time based on the queue and perform the action specified by the function. Imagine what'd happen if the functions weren't anonymous. The code would tell everyone to wake up at once while the queue was being built. And Mafia is of course pointless if everyone wakes up at once!

I hope this helps the weirdly large number of CS students in Mafia Club, or anyone else interested in coding. For more information, read your programming language's documentation on lambda expressions.


How Automod Works

automod.html

automod.html just contains HTML code for the various interfaces. It consists mostly of popups that are shown at appropriate points in gameplay.

auto.json

A list of the roles that have been coded, aka the list of roles that Automod can put in games. That was the easy part. Now for the much more complicated JavaScript files.

roleProps.js

While the roles and their descriptions are requested from https://github.com/mafiaclub/mafiaclub.github.io, roleProps.js contains the roles' data, like the number of shots they can survive, whether or not they affect guilt checks, and most importantly, the functions that make up each role's ability. Abilities are returned by getSkill as functions that contain the action to be performed. Information seen by info roles is a function similarly returned by getInfo. This is a separate file from automod.js because the sheer number of role abilities would make it very long.

automod.js

Now the gory detail. This file defines all the functions for the gameplay loop, which works as below. Of course, I won't go into every line of code.

  1. As soon as the page loads, init() loads the role data.
  2. When the game is started, giveRoles() validates the names before giving each player a random number

More notes coming soon…perhaps.