# Exercise: Arcade Token Counters

Write the Starlight Arcade's token counters, prize-ticket machine and once-only welcome bonus, each keeping its count private in a closure, and let the tests check each one.

Journeyman · JavaScript · Updated October 30, 2026

The Starlight Arcade is retiring its paper token cards. Every player needs a counter for their tokens that nobody else's game can touch, every prize-ticket machine needs to keep its own running total, and every new player gets a welcome bonus of 10 free tokens that must work exactly once, however many times they tap the button. Those are three closures for you to write, with no global variables anywhere, and tests check every one as you go.

## Get the exercise code

In the **Exercise** box beside the lesson, choose **Get the starter on GitHub** to open its GitHub repository. Click **Code**, then **Download ZIP**, and unzip it where you keep your practice folders. Or clone it with Git.

The folder holds:

- `arcade.js`: the three functions, for you to finish.
- `play.js`: runs a visit to the arcade with your functions and prints what happens. Ready to use.
- `arcade.test.js`: the tests that check your functions. You don't need to change it.
- `package.json`: tells Node.js how to run the code and its tests. Ready to use.

Open the folder in VS Code, and open a terminal there with **Terminal > New Terminal**.

## What to do

Every function is already declared and returns a placeholder for now. The comment above each one says what it should do, with examples:

```javascript
// 2. makeTicketMachine()
//    Make a prize-ticket machine. It returns a function, addTickets(tickets), that adds the tickets a player
//    won to the machine's total and returns the new total. The total starts at 0.
//    Called with no tickets at all, it adds nothing and returns the total so far: give tickets a default value.
//    const tickets = makeTicketMachine();
//    tickets(12) -> 12
//    tickets(30) -> 42
//    tickets()   -> 42
export function makeTicketMachine() {
  return (tickets) => 0;
}
```

1. **Finish `makeTokenCounter(start)`.** It returns an object with three functions: `check()` gives the player's tokens, `add(amount)` adds some and returns the new count, and `spend(amount)` takes them away and returns `true`, or returns `false` and changes nothing when the player doesn't have enough. The count lives in a variable inside `makeTokenCounter`, never in a property of the object.
2. **Finish `makeTicketMachine()`.** It returns one function that adds a win to the machine's total and returns the total so far.
3. **Finish `once(action)`.** It returns a new function that calls `action` the first time, with the arguments it was given, and returns its result. Every later call returns that same first result, and `action` never runs again. The arcade uses it for the welcome bonus.

No variables outside the functions: two players' counters, or two ticket machines, must never share a count.

## Check your work

Run the tests from the terminal:

```bash
node --test
```

At first all 12 tests fail. That's expected: each function you finish turns its tests green. When a test fails, its message says what it expected, for example *With 5 tokens, spend(8) returns false.* A test named *every counter keeps its own tokens* that stays red usually means a count is kept outside the function, where every counter shares it.

To see your counters at work in a visit to the arcade, run:

```bash
node play.js
```

## Hints

- **Start from a worked example.** The lives counter in *Closures at Work: Private State and Factories* has the same shape as the token counter: one private variable, and an object of arrow functions that share it.
- **Decide before you change.** `spend` has two outcomes. Check whether the player has enough tokens first, and only then change the count.
- **A default value fills a gap.** `(tickets = 0) =>` uses 0 when the caller leaves the argument out (see *Function Expressions and Arrow Functions*).
- **`once` remembers two things.** The `once` in the lesson keeps one flag. Yours also needs to keep what `action` returned the first time, so later calls can hand it back.
- **Passing on arguments you don't know yet.** A rest parameter, `(...args)`, collects whatever the caller passes, and spread, `action(...args)`, hands them on. *Spread and Rest* shows both.

## When you're done

All 12 tests are green, and `node play.js` prints:

```text
Ava arrives with 20 tokens.
Ava claims her welcome bonus: 30 tokens.
Ava tries to claim it again: still 30 tokens.
Ava plays Space Blaster (2 tokens): game on!
Ava has 28 tokens left.
Leo tries the claw machine (8 tokens): not enough tokens
Leo has 5 tokens left.
Prize tickets after Skee-Ball: 35
Prize tickets after Whack-a-Mole: 55
Prize tickets to spend at the prize counter: 55
```

Now look back at your code. Is there any variable outside your three functions that other code could use to change a player's tokens? If there is, move it inside, where only its own functions can reach it.

## So what

You've built counters that guard their own data: nothing outside them can hand out free tokens or erase a player's tickets. The same pattern keeps a shopping cart's total honest, stops a payment button from charging twice, and sits inside many of the libraries you'll use.

## Key terms

- [Closure](https://www.ask-codey.com/glossary/closure-javascript)
- Factory Function
- [Encapsulation](https://www.ask-codey.com/glossary/encapsulation-javascript)
- [Default Parameter](https://www.ask-codey.com/glossary/default-parameter)

## Related

- [Closures: Functions That Remember](https://www.ask-codey.com/lessons/javascript-closures-functions-that-remember)
- [Closures at Work: Private State and Factories](https://www.ask-codey.com/lessons/javascript-closures-private-state-and-factories)
- [Scope: Where a Variable Can Be Seen](https://www.ask-codey.com/lessons/javascript-scope-where-variables-live)

Source: https://www.ask-codey.com/lessons/exercise-javascript-arcade-token-counters
