Named counters with closures

Write makeCounter(), and use one counter for each name.

What to build

A function that returns a new counting function, and a program that keeps one of them per name.

Requirements

  • makeCounter() returns a function that counts how many times it has been called. It returns 1, then 2, and so on.
  • tick NAME: count one for NAME and print NAME is now N.
  • show NAME: print NAME is N, or 0 if NAME has never ticked, without counting.

Input

Several lines, each a command.

Output

One line per command.

Constraints

There are from 1 to 100 commands. Names are lower-case letters.

Example

Input:

tick a
tick a
show b

Output:

a is now 1
a is now 2
b is 0

Why it works

Each call of makeCounter creates its own hidden count, so the counters can never disturb one another, and nothing outside can change them except by calling them.

Examples

Example 1 · Input
tick a
tick a
show b
Expected output
a is now 1
a is now 2
b is 0
Example 2 · Input
show x
tick x
show x
Expected output
x is 0
x is now 1
x is 1

Hints

Hint 1

makeCounter() returns a function that adds 1 to its own count and returns it.

Hint 2

Keep the counters in an object: counters[name] ??= makeCounter().

Hint 3

Read lines until prompt() gives null; split each into the command and the name.

Solution

Show one correct solution (try it yourself first)
function makeCounter() {
  let count = 0;
  return () => ++count;
}

const counters = {};
const totals = {};
let line = prompt();
while (line !== null) {
  const [command, name] = line.split(" ");
  if (command === "tick") {
    counters[name] ??= makeCounter();
    totals[name] = counters[name]();
    console.log(`${name} is now ${totals[name]}`);
  } else {
    console.log(`${name} is ${totals[name] ?? 0}`);
  }
  line = prompt();
}

Lesson: Scope and closures →