Calculator Enactment - Live Performance Script

Your team of 15 will act out how a calculator actually works using Reverse Polish Notation. This isn’t a presentation - you’re physically becoming the algorithm.

What You’re Doing

You’re going to physically act out how a calculator works. Not a simple calculator - the RPN (Reverse Polish Notation) algorithm that computers actually use.

Why this matters: You’ll see three data structures (HashMap, ArrayList, Stack) working together to solve one problem. This is how real code works - multiple structures collaborating.

What to expect: About 5-7 minutes of performance. You’ll transform “5 + 3 * 2” into an answer by being the algorithm. Some of you will be numbers, some will be operators, some will manage the data structures.

Goal: Make the class understand why precedence matters and how stacks make it work.

Team Setup (15 People)

Director (1) - Narrates to the class, explains what’s happening
Tokenizer (1) - Calls out each character, sends tokens to queue
RPN Boss (1) - Controls the operator stack, makes precedence decisions
Calculator (1) - Runs the final calculations
Data Structure Explainers (2) - Explain HashMap, ArrayList, Stack as they’re used
Tokens (9) - You ARE the numbers and operators (use phones to show your value)

Props: Phones with big numbers, tape on floor for stations, chairs for “stacks”

SCRIPT: Hard Version √(3^2 + 4^2) - Pythagorean Theorem

Yash (Director): “OKAY. Final round. The LEGENDARY Pythagorean Theorem: √(3^2 + 4^2). Ten tokens. Multiple exponents. A square root that’s basically running a DICTATORSHIP. Who’s ready?”

[wait for energy]

Aadi (Data Structure Explainer): “Square root is precedence 1. Exponent is precedence 2. Plus is 4. Lower number = MORE IMPORTANT. So square root is literally the KING. Watch it RULE.”

Interactive Tokenize

Yash (Director): “I’m going to introduce each token. You CLAP when you see a NUMBER, you STOMP when you see an OPERATOR, and you FREEZE when you see a PARENTHESIS. Let’s GO!”

Risha (Tokenizer): “Rohan, square root operator!” [STOMP] Risha (Tokenizer): “Ruta, open paren!” [FREEZE - Ruta walks forward] Risha (Tokenizer): “Yash, 3!” [CLAP - Yash walks forward] Risha (Tokenizer): “Yuva, exponent operator!” [STOMP] Risha (Tokenizer): “Anvay, 2!” [CLAP - Anvay walks forward] Risha (Tokenizer): “Mihir, plus!” [STOMP - Mihir walks forward] Risha (Tokenizer): “Ansh, 4!” [CLAP - Ansh walks forward] Risha (Tokenizer): “Yuva, exponent operator again!” [STOMP] Risha (Tokenizer): “Anvay, 2!” [CLAP - Anvay walks forward] Risha (Tokenizer): “Vibha, close paren!” [FREEZE - Vibha walks forward]

Yash (Director): “TEN tokens! Count them on your fingers. Did you get ten?” [show hands] “Good. You’re TRACKING this.”


RPN Time - PREDICTION GAME

Yash (Director): “Here’s the deal. Ten tokens. But their ORDER is about to GET WEIRD. Who thinks the square root will be FIRST in the final RPN?” [hands] “Who thinks it’ll be LAST?” [hands] “Watch this…”

Nikhil (RPN Boss): “Rohan, square root, onto the stack!” [√ sits on the HIGH CHAIR - the THRONE]

AUDIENCE: “SQUARE ROOT IS THE KING!”

Nikhil (RPN Boss): “Ruta, open paren, stack it!” [Ruta sits below, subordinate]

Nikhil (RPN Boss): “Yash, 3, you’re a number. RPN output!” [Yash moves out, audience whispers: “Yash is free…”]

Nikhil (RPN Boss): “First exponent—precedence 2. Stack is just paren so get on!” [Exponent operator sits on a regular chair, feels important]

Nikhil (RPN Boss): “Anvay, 2, to RPN!” [Anvay moves]

Nikhil (RPN Boss): “Mihir, plus sign—precedence 4. But exponent is precedence 2. Who’s MORE important? EXPONENT IS!”

Nikhil (RPN Boss): “Everyone SCREAM when exponent gets ejected!” [Exponent launches to RPN] EVERYONE: “AHHHHHHHHH!”

Yash (Director): “BRUTAL. The exponent said ‘I don’t CARE about Mihir, I’m OUT.’”

Nikhil (RPN Boss): “Now Mihir, plus, get on the stack.” [Mihir sits, wary]

Nikhil (RPN Boss): “Ansh, 4, RPN!” [Ansh moves]

Nikhil (RPN Boss): “Second exponent. Mihir is precedence 4, I’m precedence 2. I’m MORE important!” [Mihir gets yeeted] EVERYONE: “OOOOH!”

Nikhil (RPN Boss): “Now I’m on.” [Exponent sits]

Nikhil (RPN Boss): “Anvay, 2, RPN!” [Anvay moves]

Nikhil (RPN Boss): “Vibha, close paren—dump EVERYTHING!” [Exponent launches] EVERYONE: “POP!” [Mihir launches] EVERYONE: “POP!” [Ruta vanishes] EVERYONE: “PAREN IS GONE!”

Yash (Director): “Square root is STILL up there. THE KING WAITS.”

Nikhil (RPN Boss): “No more tokens. Stack is clear!” [√ descends in slow motion] EVERYONE: “THE KING IS COMING DOWN!”

[√ walks to RPN] EVERYONE: “THE KING IS LAST!”

Yash (Director): “FINAL RPN: [3, 2, ^, 4, 2, ^, +, √]. Remember when the square root was FIRST? NOW IT’S LAST. The algorithm made it WAIT. Democracy in action.”


Calculate - MATH OLYMPICS

Yash (Director): “Here’s the deal. I’m the ANNOUNCER, the cast is the COMPETITORS, you’re the JUDGES. You tell them if they’re RIGHT. Ready? Let’s GO!”

Aditya Katre (Calculator): “Yash’s 3 on the stack. Anvay’s 2 on the stack. EXPONENT!”

AUDIENCE (yelling): “3 to the power of 2! 9!”

[Yash updates to 9, everyone CHEERS]

Yash (Director): “IS THAT RIGHT? Yash’s 3 to the power of Anvay’s 2. That means 3 * 3, right? Somebody say it!”

AUDIENCE: “3 TIMES 3 IS 9!”

Aditya Katre (Calculator): “Stack Ansh’s 4. Stack Anvay’s 2. EXPONENT!”

AUDIENCE: “4 SQUARED IS 16!”

[Ansh updates to 16, the ROOM IS PUMPED]

Yash (Director): “Okay, we have 9 and 16. What are these?” [wait for answers] “RIGHT. We have squared numbers. From a right triangle. This is ABOUT to be RELEVANT.”

Aditya Katre (Calculator): “Plus ‘em! 9 + 16!”

AUDIENCE (yelling calculations at each other): “25!”

[Rohan updates to 25]

AUDIENCE (spontaneously): “THAT’S A PERFECT SQUARE!”

Yash (Director): “WAIT, YOU’RE RIGHT. 5 squared is 25. We’re about to see the 5. The algorithm KNEW.”

Aditya Katre (Calculator): “SQUARE ROOT OF 25!”

EVERYONE (LOSING IT): “FIVE!!!!!!”

[CHAOS. Celebration. Everyone takes bows]

Yash (Director): “FIVE! 3-4-5 RIGHT TRIANGLE! THE PYTHAGOREAN THEOREM just WALKED INTO YOUR CLASSROOM and PERFORMED with Rohan, Ruta, Yash, Yuva, Anvay, Mihir, Ansh, and Vibha! How many of you just understood the WHOLE ALGORITHM?”

[raise hands, count them]

Pranav (Data Structure Explainer): “The square root WAITED until the END because parentheses forced the exponents to WIN FIRST. Stack power. Patience wins.”

Aadi (Data Structure Explainer): “HashMap knew square root takes ONE number, not two. PRECISION. This is why computers are BETTER at math than humans—no emotions, just RULES.”

Yash (Director): “And THAT’S three data structures working together. ArrayLists for order, Stacks for precedence and waiting, HashMaps for RULES. Three tools, infinite power. You all just SAW it. You all FELT it. You’re computer scientists now. Congratulations to Rohan, Ruta, Yash, Yuva, Anvay, Mihir, Ansh, and Vibha. Give them the standing ovation they deserve.”

[genuine applause moment]

Quick Tips

Before You Perform:

  • Download a big number app on your phone (search “LED display” or “big text”)
  • Practice switching values fast (3 → 6 → 11)
  • Run through it twice - once slow, once at performance speed
  • Use tape on the floor to mark where tokens stand

During the Performance:

  • SPEAK LOUD - the class needs to hear you
  • Move between stations - don’t just stand there
  • Make eye contact when “calculating” with another token
  • ham it up when parentheses “disappear” or when two tokens “compress”

Common Mistakes:

  • Mixing up pop order (first pop = second operand!)
  • Forgetting precedence (lower number = higher priority)
  • Rushing - slow down, let people understand

The Point: You’re not just acting. You’re showing how THREE data structures (HashMap, ArrayList, Stack) work together to solve one problem. Make that clear!

Data Structures - What You’re Actually Showing

HashMap (in the operators)

  • Like a cheat sheet - instant lookup of operator precedence
  • O(1) speed - super fast
  • In your enactment: The RPN Boss has a reference card

ArrayList (the token lists and RPN output)

  • Keeps things in order
  • Like a line at lunch - first in stays first
  • In your enactment: Tokens line up horizontally

Stack (operator stack + calculation stack)

  • Last in, first out (LIFO)
  • Like a stack of plates - only touch the top one
  • In your enactment: Tokens stand vertically, only the front person can leave
  • THIS is how we handle precedence and calculations!

The Combo: All three work together. HashMap tells us rules. ArrayList keeps order. Stack makes it actually compute correctly.

Testing the Code

Run the calculator with your enactment expressions to verify the results:

import java.util.function.BiFunction;

/**
 * Token class represents fundamental components of a mathematical expression
 */
public class Token {
    private final Character token;
    private final int precedence;
    private final BiFunction<Double, Double, Double> calculation;
    private final int numArgs;

    public Token() {
        this('0');
    }

    public Token(Character token) {
        this(token, 0, null, 0);
    }

    public Token(Character token, int precedence, BiFunction<Double, Double, Double> calculation, int numArgs) {
        this.token = token;
        this.precedence = precedence;
        this.calculation = calculation;
        this.numArgs = numArgs;
    }

    public Character getToken() {
        return token;
    }

    public int getPrecedence() {
        return precedence;
    }

    public int getNumArgs() {
        return numArgs;
    }

    public boolean isPrecedent(Token token) {
        return this.precedence > token.getPrecedence();
    }

    public Double calculate(Double operand1, Double operand2) {
        return this.calculation.apply(operand1, operand2);
    }

    public String toString() {
        return this.token.toString();
    }
}
import java.util.function.BiFunction;

/**
 * TermOrOperator class extends Token
 * Represents either a value, operator, or parenthesis
 */
public class TermOrOperator extends Token {
    private final String value;

    // Constructor for values
    public TermOrOperator(String value) {
        this.value = value;
    }

    // Constructor for parenthesis
    public TermOrOperator(Character token) {
        super(token);
        this.value = null;
    }

    // Constructor for operators
    public TermOrOperator(Character token, int precedence, BiFunction<Double, Double, Double> calculation) {
        super(token, precedence, calculation, 2);
        this.value = null;
    }

    // Constructor for operators with custom arg count
    public TermOrOperator(Character token, int precedence, BiFunction<Double, Double, Double> calculation, int numArgs) {
        super(token, precedence, calculation, numArgs);
        this.value = null;
    }

    public String getValue() {
        return value;
    }

    public String toString() {
        if (this.value == null) {
            return super.toString();
        }
        return this.value;
    }
}
import java.util.Map;
import java.util.function.BiFunction;
import java.util.HashMap;

/**
 * Tokens class manages a collection of operators and separators
 * Uses HashMap for O(1) lookup performance
 */
public class Tokens {
    private Map<Character, TermOrOperator> map;

    public Tokens() {
        this.map = new HashMap<>();
    }

    // Put method for parenthesis and separators
    public void put(Character token) {
        this.map.put(token, new TermOrOperator(token));
    }

    // Put method for operators with custom arg count
    public void put(Character token, int precedence, BiFunction<Double, Double, Double> calculation, int numArgs) {
        this.map.put(token, new TermOrOperator(token, precedence, calculation, numArgs));
    }

    // Put method for binary operators
    public void put(Character token, int precedence, BiFunction<Double, Double, Double> calculation) {
        this.map.put(token, new TermOrOperator(token, precedence, calculation));
    }

    public TermOrOperator get(Character token) {
        return this.map.get(token);
    }

    public int getPrecedence(Character token) {
        return this.map.get(token).getPrecedence();
    }

    public boolean contains(Character token) {
        return this.map.containsKey(token);
    }

    public String toString() {
        return this.map.toString();
    }
}
import java.util.ArrayList;
import java.util.Stack;

/**
 * Calculator class - converts mathematical expressions to RPN and calculates result
 * This is the main class that demonstrates the algorithm you'll enact
 */
public class Calculator {
    private final String expression;
    private ArrayList<TermOrOperator> terms = new ArrayList<>();
    private ArrayList<TermOrOperator> rpnTerms = new ArrayList<>();
    private Tokens operators = new Tokens();
    private Tokens seperators = new Tokens();
    private Double result = 0.0;

    public Calculator(String expression) {
        initOperators();
        initSeperators();
        this.expression = expression;
        this.termTokenizer();
        this.termsToRPN();
        this.rpnToResult();
    }

    /**
     * Initialize operators with precedence and calculation
     * Lower precedence number = higher priority
     */
    private void initOperators() {
        operators.put('^', 2, (a, b) -> Math.pow(a, b));
        operators.put('*', 3, (a, b) -> a * b);
        operators.put('/', 3, (a, b) -> a / b);
        operators.put('%', 3, (a, b) -> a % b);
        operators.put('+', 4, (a, b) -> a + b);
        operators.put('-', 4, (a, b) -> a - b);
        operators.put('√', 1, (a, b) -> Math.sqrt(a), 1);
    }

    private void initSeperators() {
        seperators.put(' ');
        seperators.put('(');
        seperators.put(')');
    }

    /**
     * PHASE 1: Tokenization
     * Breaks expression into individual terms/operators
     */
    private void termTokenizer() {
        int start = 0;
        StringBuilder multiCharTerm = new StringBuilder();
        for (int i = 0; i < this.expression.length(); i++) {
            Character c = this.expression.charAt(i);

            if (operators.contains(c) || seperators.contains(c)) {
                if (multiCharTerm.length() > 0) {
                    this.terms.add(new TermOrOperator(this.expression.substring(start, i)));
                }
                TermOrOperator t = operators.get(c);
                if (t == null) {
                    t = seperators.get(c);
                }
                if (t != null && t.getToken() != ' ') {
                    this.terms.add(t);
                }
                start = i + 1;
                multiCharTerm = new StringBuilder();
            } else {
                multiCharTerm.append(c);
            }
        }
        if (multiCharTerm.length() > 0) {
            this.terms.add(new TermOrOperator(this.expression.substring(start)));
        }
    }

    /**
     * PHASE 2: Convert to RPN using Shunting-Yard algorithm
     * This is the complex part you'll enact with the operator stack!
     */
    private void termsToRPN() {
        Stack<TermOrOperator> operatorStack = new Stack<>();

        for (TermOrOperator term : terms) {
            if (term.getToken() == '(') {
                operatorStack.push(term);
            } else if (term.getToken() == ')') {
                while (operatorStack.peek() != null && operatorStack.peek().getToken() != '(') {
                    rpnTerms.add(operatorStack.pop());
                }
                operatorStack.pop(); // remove '('
            } else if (operators.contains(term.getToken())) {
                while (!operatorStack.isEmpty() && 
                       operators.contains(operatorStack.peek().getToken()) && 
                       term.isPrecedent(operatorStack.peek())) {
                    rpnTerms.add(operatorStack.pop());
                }
                operatorStack.push(term);
            } else {
                this.rpnTerms.add(term);
            }
        }
        while (!operatorStack.isEmpty()) {
            rpnTerms.add(operatorStack.pop());
        }
    }

    /**
     * PHASE 3: Calculate result from RPN
     * This is where the calculation stack comes in!
     */
    private void rpnToResult() {
        Stack<Double> calcStack = new Stack<Double>();

        for (TermOrOperator term : this.rpnTerms) {
            Double operand1 = 0.0, operand2 = 0.0, result = 0.0;

            if (operators.contains(term.getToken())) {
                if (term.getNumArgs() == 1) {
                    operand1 = calcStack.pop();
                } else {
                    operand2 = calcStack.pop();
                    operand1 = calcStack.pop();
                }
                result = term.calculate(operand1, operand2);
                calcStack.push(result);
            } else {
                calcStack.push(Double.valueOf(term.getValue()));
            }
        }
        this.result = calcStack.pop();
    }

    public String toString() {
        return ("Original expression: " + this.expression + "\n" +
                "Tokenized expression: " + this.terms.toString() + "\n" +
                "Reverse Polish Notation: " + this.rpnTerms.toString() + "\n" +
                "Final result: " + String.format("%.2f", this.result));
    }
}
/**
 * Main class to test the Calculator with enactment examples
 */
public class CalculatorTester {
    public static void main(String[] args) {
        System.out.println("=== SIMPLE EXAMPLE ===");
        Calculator simple = new Calculator("5 + 3 * 2");
        System.out.println(simple);
        System.out.println();

        System.out.println("=== INTERESTING EXAMPLE (with parentheses) ===");
        Calculator interesting = new Calculator("(10 + 5) * 2 - 3");
        System.out.println(interesting);
        System.out.println();

        System.out.println("=== ADVANCED EXAMPLE (Pythagorean Theorem) ===");
        Calculator advanced = new Calculator("√(3^2 + 4^2)");
        System.out.println(advanced);
        System.out.println();

        System.out.println("=== BONUS: Complex Expression ===");
        Calculator bonus = new Calculator("100 + 200 * 3");
        System.out.println(bonus);
    }
}

CalculatorTester.main(null);
=== SIMPLE EXAMPLE ===
Original expression: 5 + 3 * 2
Tokenized expression: [5, +, 3, *, 2]
Reverse Polish Notation: [5, 3, 2, *, +]
Final result: 11.00

=== INTERESTING EXAMPLE (with parentheses) ===
Original expression: (10 + 5) * 2 - 3
Tokenized expression: [(, 10, +, 5, ), *, 2, -, 3]
Reverse Polish Notation: [10, 5, +, 2, *, 3, -]
Final result: 27.00

=== ADVANCED EXAMPLE (Pythagorean Theorem) ===
Original expression: √(3^2 + 4^2)
Tokenized expression: [√, (, 3, ^, 2, +, 4, ^, 2, )]
Reverse Polish Notation: [3, 2, ^, 4, 2, ^, +, √]
Final result: 5.00

=== BONUS: Complex Expression ===
Original expression: 100 + 200 * 3
Tokenized expression: [100, +, 200, *, 3]
Reverse Polish Notation: [100, 200, 3, *, +]
Final result: 700.00

Your Blog Write-Up

What to Include:

  1. Team members and who did what
  2. Which expressions you used and why
  3. Photos or video of the performance
  4. Explain the three data structures (HashMap, ArrayList, Stack) and where each was used
  5. What went wrong and how you fixed it

Questions to Answer:

  • Why is RPN easier for computers than regular math notation?
  • How does Stack help with operator precedence?
  • Why HashMap instead of a bunch of if statements?
  • Where else would you use stacks in programming?

Grading:

  • Can people understand what’s happening? (40%)
  • Did you get the algorithm right? (30%)
  • Did your team work smoothly? (15%)
  • Is your blog complete? (15%)

Cheat Sheet

Precedence (lower number = do it first):

  • √ = 1
  • ^ = 2
  • *, /, % = 3
  • +, - = 4

The Algorithm:

  1. Tokenize: Break expression into pieces
  2. RPN: Numbers go straight through. Operators wait on stack based on precedence. Parentheses control when things pop.
  3. Calculate: Stack numbers. When you hit an operator, pop two, calculate, push result back.

Remember:

  • First pop = second operand (order matters!)
  • Parentheses don’t make it to RPN (they just control the stack)
  • Lower precedencenumber means do it first