Module 37

Social Deduction

Build a game where trust is a weapon and suspicion is a strategy | Who Among Us?

"In a game of perfect information, the best player wins. In a game of hidden information, the best liar wins."

Prerequisites

ModuleWhat You Used From It
Module 01 - PongA working game loop and basic input handling.
Module 35 - Party GameMultiplayer input handling, lobby/join systems, and round-based game structure. Social deduction builds on the party game framework with hidden roles and asymmetric information.

Week 1: History & Design Theory

The Origin

The social deduction genre was invented in the psychology department of Moscow State University. In 1986, Dimitry Davidoff created Mafia as a classroom exercise exploring the tension between an informed minority and an uninformed majority. The rules were elegant: a small group of "mafia" members secretly chose someone to eliminate each night, while the larger group of "townspeople" debated during the day about who to vote out. No board, no cards, no technology — just people, deception, and the human inability to reliably detect lies. Mafia spread virally through campuses and social circles across the Soviet Union and eventually worldwide. It proved that the most compelling game mechanic is not any system a designer can build but rather the human instinct to read faces, challenge stories, and construct theories about who is lying.

How the Genre Evolved

Mafia / Werewolf (Dimitry Davidoff, 1986; Andrew Plotkin, 1997) — Mafia established the genre's DNA: hidden roles, day/night cycles, group discussion, and elimination voting. Andrew Plotkin's re-skin as "Werewolf" in 1997 added thematic flavor and made the game more accessible to Western audiences. The core insight was that the game needed no referee AI, no complex rules, and no technology — just a social contract where some players lie and others try to catch them.

Town of Salem (BlankMediaGames, 2014) — Brought social deduction to the browser with dozens of unique roles (Sheriff, Doctor, Serial Killer, Jester), text-based chat for discussion, and automated night phases. Town of Salem proved the genre could work digitally without voice chat or physical presence. The Jester role — a player who wins by tricking others into voting them out — showed that asymmetric win conditions create emergent gameplay.

Among Us (InnerSloth, 2018/2020) — Replaced the text-based discussion format with real-time spatial gameplay. Crewmates walk around a map completing tasks while impostors sabotage and kill. The genius of Among Us was giving players physical alibis: "I was in Medbay doing the scan" is verifiable if someone else was there too. Among Us became a global phenomenon during 2020 by combining accessible controls, short game sessions, and the irresistible drama of accusing friends of murder.

What Makes It "Great"

A great social deduction game creates genuine tension from asymmetric knowledge. The impostors know everything; the crew knows almost nothing. This imbalance generates the core emotions: paranoia for the crew, exhilaration for the impostors, and mounting dread for everyone as the player count shrinks. The discussion phase is where the game truly lives — accusation, defense, alliance, and betrayal all happen through conversation, making every group's experience unique. The best games give both sides meaningful actions so that no one is ever just waiting. And the moment of truth — the vote that eliminates a player, the reveal of whether they were innocent or guilty — must land with weight.

The Essential Mechanic

Deception and detection — game mechanics create structured social interaction where lying is a core strategy.


Week 2: Build the MVP

What You're Building

A social deduction game for 4-8 players where one or two players are secretly assigned the "impostor" role while the rest are "crew." Crew members complete tasks to win. Impostors fake tasks and eliminate crew members. When a body is found or an emergency meeting is called, all players discuss and vote to eliminate a suspect. The game ends when all impostors are eliminated (crew wins) or impostors equal or outnumber crew (impostor wins).

Core Concepts

1. Hidden Role Assignment

At game start, roles are secretly assigned. Each player knows their own role but does not know the roles of others (except impostors, who know each other). The assignment must be random, fair, and provably hidden from other players.

function assignRoles(players, impostorCount):
    assert impostorCount < players.length / 2
    shuffled = shuffleArray(copyOf(players))
    roles = {}
    for i in range(shuffled.length):
        if i < impostorCount:
            roles[shuffled[i].id] = IMPOSTOR
        else:
            roles[shuffled[i].id] = CREW
    // Notify each player privately
    for each player in players:
        player.role = roles[player.id]
        showRoleReveal(player, roles[player.id])

// For shared-screen play: sequential role reveal
function sequentialRoleReveal(players, roles):
    for each player in players:
        showScreen("Pass the device to " + player.name)
        waitForConfirm()
        showScreen("Your role: " + roles[player.id], duration: 3 seconds)

Why it matters: The entire game rests on role secrecy. If a player's role is leaked — through a screen reflection, a tell in the UI, or a bug in the assignment — the game is ruined. The reveal sequence must be designed for the physical context and must feel dramatic, not administrative.

Interactive: Hidden Role Reveal

Click "Assign Roles" for a group of 6 players. Click each player card to peek at their role (impostor or crew). Cards flip with animation. Impostors show red, crew shows blue — only visible when peeked. Click again to hide.

Click "Assign Roles" to begin

2. Voting / Accusation System

During discussion phases, players nominate suspects and vote to eliminate someone. The player with the most votes is removed from the game. Ties and abstentions must be handled.

class VotingSystem:
    nominations = {}
    votes = {}
    alivePlayers = []
    phase = DISCUSSION

    function castVote(voterId, targetId):
        if voterId in votes: return
        if voterId NOT in alivePlayers: return
        votes[voterId] = targetId
        if votes.length == alivePlayers.length: resolveVote()

    function resolveVote():
        tallies = countVotes(votes)
        skipVotes = tallies.get(SKIP, 0)
        maxVotes = max(tallies.values())
        playersWithMax = [p for p, count in tallies if count == maxVotes AND p != SKIP]
        if skipVotes >= maxVotes OR playersWithMax.length > 1:
            showResult("No one was ejected. (Tie/Skip)")
        else:
            eliminated = playersWithMax[0]
            eliminatePlayer(eliminated)
            showResult(eliminated.name + " was ejected. They were " + eliminated.role)

Why it matters: The vote is the moment where social pressure becomes game mechanics. A wrong vote eliminates an innocent player and brings the impostors closer to victory. A correct vote removes a threat. Allowing "skip" prevents the crew from being forced into blind guesses.

Interactive: Voting System

6 player cards with hidden roles. Click a player to nominate them, then click "Vote" to cast votes. Majority rules — ties mean no elimination. After elimination, the player's role is revealed. Was it crew or impostor?

Click "New Game" to start

3. Phase-based Gameplay

The game alternates between distinct phases: a free-roam/task phase where players move and act, and a discussion/voting phase triggered by events.

GAME_PHASES:
    ROLE_REVEAL -> FREE_ROAM -> BODY_FOUND -> DISCUSSION -> VOTING -> VOTE_RESULT -> GAME_OVER

class GamePhaseManager:
    currentPhase = ROLE_REVEAL

    function update(deltaTime):
        switch currentPhase:
            case FREE_ROAM:
                updatePlayerMovement()
                updateTasks()
                updateImpostorActions()
                if bodyReported OR emergencyMeetingCalled:
                    transitionTo(BODY_FOUND)
            case DISCUSSION:
                timer -= deltaTime
                if timer <= 0: transitionTo(VOTING)
            case VOTING:
                if timer <= 0: autoSkipRemainingVoters()
            case VOTE_RESULT:
                showEjectionAnimation()
                if checkWinCondition(): transitionTo(GAME_OVER)

Why it matters: Phase separation creates rhythm. Free-roam is tense and quiet. Discussion is loud and chaotic. The shift between these modes creates an emotional roller coaster that a single-phase game cannot match.

4. Task / Objective System

Crew members have a secondary win condition: complete all tasks. Tasks give crew members a reason to move around the map and create alibis.

class TaskSystem:
    totalTaskSteps = 0
    completedTaskSteps = 0

    function completeTask(player, task):
        task.completed = true
        completedTaskSteps += 1
        updateTaskBar(completedTaskSteps / totalTaskSteps)
        if completedTaskSteps >= totalTaskSteps:
            triggerCrewWin("All tasks completed!")

Why it matters: Tasks serve three design purposes simultaneously. First, they are an alternative win condition. Second, they force movement, which creates encounters and alibis. Third, the task bar is a visible clock: if the impostors do not act fast enough, the crew will simply complete all tasks and win.

5. Kill / Sabotage Mechanics

Impostors can eliminate crew members and sabotage systems. Both actions must be performed without being seen.

class ImpostorActions:
    killCooldown = 30
    killRange = 1.5
    timeSinceLastKill = 30

    function attemptKill(impostor, target):
        if NOT canKill(): return false
        if distance(impostor.position, target.position) > killRange: return false
        if target.role == IMPOSTOR: return false
        target.alive = false
        spawnBody(target.deathPosition, target.id)
        timeSinceLastKill = 0
        return true

Why it matters: The kill cooldown is the impostor's core tension: you can only act every 30 seconds, so timing and positioning matter enormously. Sabotage adds a strategic layer — calling lights off creates cover for a kill.

6. Information Asymmetry

The fundamental mechanic of social deduction is that different players have different information. Impostors know who each other are; crew members know only their own role.

INFORMATION_RULES:
    CREW:
        knows: [own_role, own_tasks, task_bar_progress, who_is_alive]
        does_not_know: [other_roles, who_killed_whom]
    IMPOSTOR:
        knows: [own_role, other_impostors, all_crew_knows]
        sees: [sabotage_options]

Why it matters: Information asymmetry IS social deduction. Every design decision must be evaluated through the lens of "what does each player know?" The sweet spot is where crew members have enough partial information to construct theories but not enough to be certain.

7. Proximity / Visibility Mechanics

Who can see what — and who was near the body — drives spatial deduction. Vision range, line of sight, and movement tracking create physical alibis and evidence that fuel discussion.

VISION_CONFIG:
    CREW_NORMAL:     range = 5.0
    CREW_LIGHTS_OFF: range = 2.0
    IMPOSTOR:        range = 7.0
    GHOST:           range = INFINITE

Why it matters: Physical space turns abstract suspicion into concrete evidence. "I saw Red walk toward Electrical, and then the lights went off" is a deduction based on proximity and timing. The map is not just a play space — it is an information environment.


Stretch Goals

  1. Add unique crew roles with special abilities (Scanner who can confirm one player, Medic who can protect one player per night).
  2. Implement vent/shortcut system for impostors to move unseen.
  3. Add a "ghost task" system so eliminated players can still contribute.
  4. Create a post-game replay showing all player movements.
  5. Add emergency meeting cooldowns and limits.
  6. Implement a text chat or voice proximity chat system.

MVP Spec

ElementScope
Players4-8 players (networked or hot-seat with hidden role screens)
Roles2 roles: Crew and Impostor (1-2 impostors depending on player count)
MapSingle 2D map with 4-6 rooms connected by hallways
Tasks3-5 simple tasks per crew member
KillImpostors can eliminate adjacent crew members with a cooldown
ReportPlayers can report bodies they find, triggering a meeting
DiscussionTimed discussion phase (60-90 seconds)
VotingEach player votes to eliminate or skips, majority rules, ties = no elimination
Win conditionsCrew wins by completing all tasks or ejecting all impostors; Impostors win when they equal remaining crew

Deliverable

A playable social deduction game where players are assigned hidden roles, move around a 2D map, complete tasks or perform kills, report bodies to trigger discussion phases, and vote to eliminate suspects. The game must support at least 4 players with functional win conditions for both sides. A playtest session should produce genuine accusations, defenses, and the satisfying reveal of whether the voted player was crew or impostor.


Analogies by Background

These analogies map game dev concepts to patterns you already know. Find your background below.

For Backend Developers

ConceptAnalogy
Hidden role assignmentLike secrets management — each service receives its own credentials at startup, and leaking any secret compromises the system
Voting / accusation systemLike distributed consensus with Byzantine fault tolerance — the majority must agree while some nodes are actively lying
Phase-based gameplayLike a state machine in a workflow engine — each phase has entry/exit conditions and allowed actions
Task / objective systemLike background worker jobs — tasks run independently and report completion to a shared tracker
Kill / sabotage mechanicsLike a security breach simulation — an attacker operates within the system, exploiting cooldown windows
Information asymmetryLike role-based access control (RBAC) — each user sees only what their permissions allow
Proximity / visibilityLike network topology and service discovery — services can only see others within their subnet

For Frontend Developers

ConceptAnalogy
Hidden role assignmentLike personalized UI rendering — each user sees a different version based on their role
Voting / accusation systemLike a poll component with real-time results — users submit choices and the aggregated result is revealed
Phase-based gameplayLike a multi-step form wizard with conditional routing
Task / objective systemLike a progress tracker in an onboarding flow — individual steps complete independently
Kill / sabotage mechanicsLike destructive UI actions behind confirmation gates — powerful, rate-limited, context-dependent
Information asymmetryLike conditional rendering based on user role — admin sees more than regular users
Proximity / visibilityLike viewport-based lazy loading — only render elements within the visible area

For Data / ML Engineers

ConceptAnalogy
Hidden role assignmentLike train/test split labels — each data point has a hidden label, and label leakage invalidates the experiment
Voting / accusation systemLike ensemble model voting for classification — each model casts a vote and majority determines the output
Phase-based gameplayLike alternating training phases (e.g., GAN training) — different objectives and update rules alternate
Task / objective systemLike a distributed training job with a shared loss metric
Kill / sabotage mechanicsLike adversarial attacks on a model — injecting perturbations while trying to remain undetected
Information asymmetryLike the explore/exploit tradeoff in multi-armed bandits
Proximity / visibilityLike spatial locality in graph neural networks — a node can only aggregate from neighbors within a radius

Discussion Questions

  1. Designing for deception: Most games penalize dishonesty. Social deduction games require and reward it. How does designing a system where lying is valid change your approach to game rules and community management?
  2. The spectator problem: Eliminated players must wait until the game ends. Among Us partially solved this with ghost tasks. What other approaches could keep eliminated players engaged?
  3. Scaling trust: Mafia works with 7+ players in a room. Among Us works with 4-10 online. How does player count change the social dynamics? At what point is the group too small or too large?
  4. Asymmetric fun: Is it more fun to be the impostor or the crew? Most players prefer impostor, but crew outnumbers impostors 3-to-1. How do you make the crew role compelling?