feat(curriculum): add Festival Crowd Flow Simulator Workshop - JavaScript v9 (#66551)

This commit is contained in:
Luis
2026-04-23 13:28:50 -07:00
committed by GitHub
parent 2551a60d36
commit e5276cea2f
36 changed files with 3999 additions and 0 deletions

View File

@@ -4922,6 +4922,12 @@
"In this lab, you will implement loops to repeat a string a specified number of times."
]
},
"workshop-festival-crowd-flow-simulator": {
"title": "Build a Festival Crowd Flow Simulator",
"intro": [
"In this workshop, you will use JavaScript to simulate the flow of attendants at a music festival."
]
},
"lab-missing-letter-detector": {
"title": "Build a Missing Letter Detector",
"intro": [

View File

@@ -0,0 +1,75 @@
---
id: 69baafd6d683dd9921b75db3
title: Step 1
challengeType: 1
dashedName: step-1
---
# --description--
In this workshop, you will use JavaScript to simulate the flow of attendees at a music festival.
You will work with two datasets that describe the festival gates during morning and night shifts:
```js
const morningGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] },
];
const nightGates = [
{ id: "North", capacity: 4, queue: [6, 2, 5, 1] },
{ id: "East", capacity: 2, queue: [3, 3, 4, 2] },
{ id: "South", capacity: 5, queue: [2, 1, 2, 3] },
{ id: "West", capacity: 3, queue: [5, 2, 1, 4] },
];
```
Each gate object contains the following properties:
- `id`: A string that identifies the gate.
- `capacity`: The number of attendees the gate can process per tick.
- `queue`: An array of numbers representing how many attendees arrive at the gate during a specific tick.
To begin, create an empty function named `initializeThroughput` that accepts a parameter named `gates`.
# --hints--
You should create a function named `initializeThroughput`.
```js
assert.isFunction(initializeThroughput);
```
Your `initializeThroughput` function should have a `gates` parameter.
```js
const regex = __helpers.functionRegex('initializeThroughput', ['gates']);
assert.match(__helpers.removeJSComments(initializeThroughput.toString()), regex);
```
# --seed--
## --seed-contents--
```js
const morningGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] },
];
const nightGates = [
{ id: "North", capacity: 4, queue: [6, 2, 5, 1] },
{ id: "East", capacity: 2, queue: [3, 3, 4, 2] },
{ id: "South", capacity: 5, queue: [2, 1, 2, 3] },
{ id: "West", capacity: 3, queue: [5, 2, 1, 4] },
];
--fcc-editable-region--
--fcc-editable-region--
```

View File

@@ -0,0 +1,61 @@
---
id: 69bab8292750d84cac5b52a0
title: Step 2
challengeType: 1
dashedName: step-2
---
# --description--
In this workshop, throughput refers to the total number of attendees processed by a gate across all ticks in a single simulation (morning or night). Your `initializeThroughput` function will prepare an object to track how many attendees each gate processes.
First, create an empty object named `summary`.
# --hints--
Inside your `initializeThroughput` function, create an empty object and assign it to a variable named `summary`.
```js
const funcStr = __helpers.removeJSComments(initializeThroughput.toString());
assert.match(
funcStr,
/(var|let|const)\s+summary/,
"You must have at least one space between the declaration keyword (let/const) and 'summary'"
);
const cleaned = __helpers.removeWhiteSpace(__helpers.removeJSComments(initializeThroughput.toString()));
const viable_solutions = [
"functioninitializeThroughput(gates){letsummary={};}",
"functioninitializeThroughput(gates){letsummary={}}",
"functioninitializeThroughput(gates){constsummary={};}",
"functioninitializeThroughput(gates){constsummary={}}",
"functioninitializeThroughput(gates){varsummary={};}",
"functioninitializeThroughput(gates){varsummary={}}"
];
assert.include(viable_solutions, cleaned);
```
# --seed--
## --seed-contents--
```js
const morningGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] },
];
const nightGates = [
{ id: "North", capacity: 4, queue: [6, 2, 5, 1] },
{ id: "East", capacity: 2, queue: [3, 3, 4, 2] },
{ id: "South", capacity: 5, queue: [2, 1, 2, 3] },
{ id: "West", capacity: 3, queue: [5, 2, 1, 4] },
];
function initializeThroughput(gates) {
--fcc-editable-region--
--fcc-editable-region--
}
```

View File

@@ -0,0 +1,68 @@
---
id: 69babdf3f896711c11516373
title: Step 4
challengeType: 1
dashedName: step-4
---
# --description--
During each simulation tick:
- A certain number of attendees arrive at the gate (from its `queue`).
- The gate processes attendees based on its `capacity`.
- If more attendees arrive than the gate can handle, some will remain (overflow).
You will now build a function that handles this logic for one gate at a single tick.
Create an empty function named `processGateFlow` that accepts two parameters:
- `gate`: The gate object being processed.
- `tickIndex`: The current simulation tick position in the `queue` array.
# --hints--
You should create a function named `processGateFlow`.
```js
assert.isFunction(processGateFlow);
```
Your function `processGateFlow` should have parameters `gate` and `tickIndex`.
```js
const regex = __helpers.functionRegex('processGateFlow', ['gate', 'tickIndex']);
assert.match(__helpers.removeJSComments(processGateFlow.toString()), regex);
```
# --seed--
## --seed-contents--
```js
const morningGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] },
];
const nightGates = [
{ id: "North", capacity: 4, queue: [6, 2, 5, 1] },
{ id: "East", capacity: 2, queue: [3, 3, 4, 2] },
{ id: "South", capacity: 5, queue: [2, 1, 2, 3] },
{ id: "West", capacity: 3, queue: [5, 2, 1, 4] },
];
function initializeThroughput(gates) {
const summary = {};
for (const gate of gates) {
summary[gate.id] = 0;
};
return summary;
}
--fcc-editable-region--
--fcc-editable-region--
```

View File

@@ -0,0 +1,65 @@
---
id: 69babea99725b43a01adb6d1
title: Step 5
challengeType: 1
dashedName: step-5
---
# --description--
First, you need to get the number of attendees arriving during the current tick. Access the value in the input gate's `queue` array at index `tickIndex`, and assign it to a variable named `currentTickQueue`.
# --hints--
You should assign the element at `gate.queue[tickIndex]` to a variable named `currentTickQueue`.
```js
const rawFuncStr = __helpers.removeJSComments(processGateFlow.toString());
assert.match(
rawFuncStr,
/(var|const|let)\s+currentTickQueue/,
"You must have at least one space between the declaration keyword (let/const) and 'currentTickQueue'."
);
const cleaned = __helpers.removeWhiteSpace(__helpers.removeJSComments(processGateFlow.toString()));
const solution = /(var|const|let)currentTickQueue=gate\.queue\[tickIndex\];?}$/;
assert(
solution.test(cleaned),
"Inside your `processGateFlow` function, assign the element at `gate.queue[tickIndex]` to a variable named `currentTickQueue` as the only statement inside the function."
);
```
# --seed--
## --seed-contents--
```js
const morningGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] },
];
const nightGates = [
{ id: "North", capacity: 4, queue: [6, 2, 5, 1] },
{ id: "East", capacity: 2, queue: [3, 3, 4, 2] },
{ id: "South", capacity: 5, queue: [2, 1, 2, 3] },
{ id: "West", capacity: 3, queue: [5, 2, 1, 4] },
];
function initializeThroughput(gates) {
const summary = {};
for (const gate of gates) {
summary[gate.id] = 0;
};
return summary;
}
function processGateFlow(gate, tickIndex) {
--fcc-editable-region--
--fcc-editable-region--
}
```

View File

@@ -0,0 +1,66 @@
---
id: 69babf2bf78bade75fda0326
title: Step 6
challengeType: 1
dashedName: step-6
---
# --description--
Next, you need a way to track how many attendees are processed by the gate during the tick. Create a variable named `processed` and initialize it to `0`.
# --hints--
You should create a variable named `processed` and assign it a value of `0`.
```js
const rawFuncStr = __helpers.removeJSComments(processGateFlow.toString());
assert.match(
rawFuncStr,
/(var|const|let)\s+processed/,
"You must have at least one space between the declaration keyword (let/const) and 'processed'."
);
const cleaned = __helpers.removeWhiteSpace(__helpers.removeJSComments(processGateFlow.toString()));
const solution = /(var|const|let)processed=0;?}$/;
assert(
solution.test(cleaned),
"Inside your `processGateFlow` function, create a variable named `processed` and initialize it to 0."
);
```
# --seed--
## --seed-contents--
```js
const morningGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] },
];
const nightGates = [
{ id: "North", capacity: 4, queue: [6, 2, 5, 1] },
{ id: "East", capacity: 2, queue: [3, 3, 4, 2] },
{ id: "South", capacity: 5, queue: [2, 1, 2, 3] },
{ id: "West", capacity: 3, queue: [5, 2, 1, 4] },
];
function initializeThroughput(gates) {
const summary = {};
for (const gate of gates) {
summary[gate.id] = 0;
};
return summary;
}
function processGateFlow(gate, tickIndex) {
let currentTickQueue = gate.queue[tickIndex];
--fcc-editable-region--
--fcc-editable-region--
}
```

View File

@@ -0,0 +1,69 @@
---
id: 69babf3f446433af8d065bb5
title: Step 7
challengeType: 1
dashedName: step-7
---
# --description--
Create an empty `while` loop that continues as long as there are attendees waiting (`currentTickQueue > 0`) and the gate has remaining capacity (`processed < gate.capacity`).
# --hints--
Your `while` loop's condition should be `currentTickQueue > 0` and `processed < gate.capacity`.
```js
const cleaned = __helpers.removeWhiteSpace(__helpers.removeJSComments(code));
const viableSolutions = [
"while(currentTickQueue>0&&processed<gate.capacity){}}",
"while((currentTickQueue>0)&&(processed<gate.capacity)){}}",
"while(processed<gate.capacity&&currentTickQueue>0){}}",
"while((processed<gate.capacity)&&(currentTickQueue>0)){}}",
"while(currentTickQueue>0&&processed<gate.capacity){};}",
"while((currentTickQueue>0)&&(processed<gate.capacity)){};}",
"while(processed<gate.capacity&&currentTickQueue>0){};}",
"while((processed<gate.capacity)&&(currentTickQueue>0)){};}"
];
const endsCorrectly = viableSolutions.some(sol => cleaned.endsWith(sol));
assert(
endsCorrectly,
"Your while loop must have a condition with both `currentTickQueue > 0` and `processed < gate.capacity`, in any order."
);
```
# --seed--
## --seed-contents--
```js
const morningGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] },
];
const nightGates = [
{ id: "North", capacity: 4, queue: [6, 2, 5, 1] },
{ id: "East", capacity: 2, queue: [3, 3, 4, 2] },
{ id: "South", capacity: 5, queue: [2, 1, 2, 3] },
{ id: "West", capacity: 3, queue: [5, 2, 1, 4] },
];
function initializeThroughput(gates) {
const summary = {};
for (const gate of gates) {
summary[gate.id] = 0;
};
return summary;
}
function processGateFlow(gate, tickIndex) {
let currentTickQueue = gate.queue[tickIndex];
let processed = 0;
--fcc-editable-region--
--fcc-editable-region--
}
```

View File

@@ -0,0 +1,135 @@
---
id: 69babfc35c3c58d0993d404d
title: Step 9
challengeType: 1
dashedName: step-9
---
# --description--
To complete your `processGateFlow` function, return an object containing two properties:
- `processed`: The number of attendees the gate was able to process during this tick.
- `overflow`: The number of attendees left in the queue after processing (which is `currentTickQueue` after the loop).
You should directly return the object as such:
```js
return {
firstKey: firstValue,
secondKey: secondValue
}
```
# --hints--
You should return an object with properties `processed` and `overflow`. Directly return the object without assignment to a variable.
```js
const cleaned = __helpers.removeWhiteSpace(__helpers.removeJSComments(processGateFlow.toString()));
const viableSolutions = [
"return{processed:processed,overflow:currentTickQueue}}",
"return{processed:processed,overflow:currentTickQueue,}}",
"return{overflow:currentTickQueue,processed:processed,}}",
"return{overflow:currentTickQueue,processed:processed}}",
"return{processed:processed,overflow:currentTickQueue};}",
"return{processed:processed,overflow:currentTickQueue,};}",
"return{overflow:currentTickQueue,processed:processed,};}",
"return{overflow:currentTickQueue,processed:processed};}",
];
const endsCorrectly = viableSolutions.some(sol => cleaned.endsWith(sol));
assert(
endsCorrectly,
"Your processGateFlow function must return the object with processed and overflow properties."
);
const northGate = morningGates[0];
const result = processGateFlow(northGate, 0);
assert(
typeof result === 'object' && result !== null && !Array.isArray(result),
'Your function should return an object'
);
assert.hasAllKeys(
result,
['processed', 'overflow'],
'Your returned object should have properties `processed` and `overflow`'
);
```
Your returned object's `processed` property should have the value `processed`.
```js
const northGate = morningGates[0];
const result = processGateFlow(northGate, 0);
assert.strictEqual(
result.processed,
3,
'For the North gate at tick 0 with capacity 5 and queue 3, processed should be 3'
);
const westGate = morningGates[3];
const resultWest = processGateFlow(westGate, 0);
assert.strictEqual(
resultWest.processed,
2,
'For the West gate at tick 0 with capacity 2 and queue 4, processed should be 2'
);
```
Your returned object's `overflow` property should have the value `currentTickQueue`.
```js
const northGate = morningGates[0];
const result = processGateFlow(northGate, 0);
assert.strictEqual(
result.overflow,
0,
'For the North gate at tick 0 with capacity 5 and queue 3, overflow should be 0'
);
const westGate = morningGates[3];
const resultWest = processGateFlow(westGate, 0);
assert.strictEqual(
resultWest.overflow,
2,
'For the West gate at tick 0 with capacity 2 and queue 4, overflow should be 2'
);
```
# --seed--
## --seed-contents--
```js
const morningGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] },
];
const nightGates = [
{ id: "North", capacity: 4, queue: [6, 2, 5, 1] },
{ id: "East", capacity: 2, queue: [3, 3, 4, 2] },
{ id: "South", capacity: 5, queue: [2, 1, 2, 3] },
{ id: "West", capacity: 3, queue: [5, 2, 1, 4] },
];
function initializeThroughput(gates) {
const summary = {};
for (const gate of gates) {
summary[gate.id] = 0;
};
return summary;
}
function processGateFlow(gate, tickIndex) {
let currentTickQueue = gate.queue[tickIndex];
let processed = 0;
while (currentTickQueue > 0 && processed < gate.capacity) {
currentTickQueue--;
processed++;
}
--fcc-editable-region--
--fcc-editable-region--
}
```

View File

@@ -0,0 +1,77 @@
---
id: 69babfd65c4c4632a0c76f63
title: Step 10
challengeType: 1
dashedName: step-10
---
# --description--
When a gate cannot process all attendees during a tick, some attendees remain in the queue. To handle this overflow, you will build a function that reroutes overflow attendees to another gate.
Create an empty function named `rerouteOverflow` with the following parameters:
- `gates`: The full array of gate objects.
- `currentGate`: The gate where the overflow occurred.
- `tickIndex`: The current tick position in the queue.
- `overflowAmount`: The number of attendees that could not be processed.
# --hints--
You should create a function named `rerouteOverflow`.
```js
assert.isFunction(rerouteOverflow);
```
Your `rerouteOverflow` function should have parameters `gates`, `currentGate`, `tickIndex`, and `overflowAmount`.
```js
const regex = __helpers.functionRegex('rerouteOverflow', ['gates', 'currentGate', 'tickIndex', 'overflowAmount']);
assert.match(__helpers.removeJSComments(rerouteOverflow.toString()), regex);
```
# --seed--
## --seed-contents--
```js
const morningGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] },
];
const nightGates = [
{ id: "North", capacity: 4, queue: [6, 2, 5, 1] },
{ id: "East", capacity: 2, queue: [3, 3, 4, 2] },
{ id: "South", capacity: 5, queue: [2, 1, 2, 3] },
{ id: "West", capacity: 3, queue: [5, 2, 1, 4] },
];
function initializeThroughput(gates) {
const summary = {};
for (const gate of gates) {
summary[gate.id] = 0;
};
return summary;
}
function processGateFlow(gate, tickIndex) {
let currentTickQueue = gate.queue[tickIndex];
let processed = 0;
while (currentTickQueue > 0 && processed < gate.capacity) {
currentTickQueue--;
processed++;
}
return {
processed: processed,
overflow: currentTickQueue
};
}
--fcc-editable-region--
--fcc-editable-region--
```

View File

@@ -0,0 +1,86 @@
---
id: 69bac013466bd9bad0b809b1
title: Step 11
challengeType: 1
dashedName: step-11
---
# --description--
First, you will find the position of a specific gate within the `gates` array.
Use the `indexOf()` method on `gates` to locate the `currentGate` element and assign the result to a variable named `currentIndex`.
Here is a refresher on how this can be done:
```js
const index = array.indexOf(element);
```
# --hints--
You should use `indexOf()` on the `gates` array to access the index of `currentGate` and assign it to a variable named `currentIndex`. This should be done in one line.
```js
const rawFuncStr = __helpers.removeJSComments(rerouteOverflow.toString());
assert.match(
rawFuncStr,
/(var|const|let)\s+currentIndex/,
"You must have at least one space between the declaration keyword (let/const) and 'currentIndex'."
);
const cleaned = __helpers.removeWhiteSpace(rawFuncStr);
const solution = /(var|const|let)currentIndex=gates\.indexOf\(currentGate\);?}$/;
assert(
solution.test(cleaned),
"Inside your `rerouteOverflow` function, use `indexOf()` on the `gates` array to access the index of `currentGate` and assign it to a variable named `currentIndex`."
);
```
# --seed--
## --seed-contents--
```js
const morningGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] },
];
const nightGates = [
{ id: "North", capacity: 4, queue: [6, 2, 5, 1] },
{ id: "East", capacity: 2, queue: [3, 3, 4, 2] },
{ id: "South", capacity: 5, queue: [2, 1, 2, 3] },
{ id: "West", capacity: 3, queue: [5, 2, 1, 4] },
];
function initializeThroughput(gates) {
const summary = {};
for (const gate of gates) {
summary[gate.id] = 0;
};
return summary;
}
function processGateFlow(gate, tickIndex) {
let currentTickQueue = gate.queue[tickIndex];
let processed = 0;
while (currentTickQueue > 0 && processed < gate.capacity) {
currentTickQueue--;
processed++;
}
return {
processed: processed,
overflow: currentTickQueue
};
}
function rerouteOverflow(gates, currentGate, tickIndex, overflowAmount) {
--fcc-editable-region--
--fcc-editable-region--
}
```

View File

@@ -0,0 +1,89 @@
---
id: 69bac027df64d4433c708d44
title: Step 12
challengeType: 1
dashedName: step-12
---
# --description--
When rerouting overflow, you should send attendees to the next gate in the `gates` array. To do this, you need to find the index of the next gate. Normally, you could add 1 to the current index. However, if the current gate is the last one in the array, you need to wrap back to the first gate.
You can use the modulo operator (`%`) to handle this:
```js
const nextIndex = (currentIndex + 1) % array.length;
```
This works because when `currentIndex + 1` equals the `array.length`, the result becomes 0.
Using this approach, create a variable named `nextGateIndex` that stores the index of the next gate in the `gates` array.
# --hints--
You should use the modulo technique to access and assign the next index from `currentIndex` in the `gates` array to a variable named `nextGateIndex`. Follow the same one-line pattern in the example.
```js
const rawFuncStr = __helpers.removeJSComments(rerouteOverflow.toString());
assert.match(
rawFuncStr,
/(var|const|let)\s+nextGateIndex/,
"You must have at least one space between the declaration keyword (let/const) and 'nextGateIndex'."
);
const cleaned = __helpers.removeWhiteSpace(rawFuncStr);
const solution = /(var|const|let)nextGateIndex=\((currentIndex\+1|1\+currentIndex)\)%gates\.length;?}$/;
assert(
solution.test(cleaned),
"Inside your `rerouteOverflow` function, use the modulo technique to create a variable named `nextGateIndex` that stores the index of the next gate."
);
```
# --seed--
## --seed-contents--
```js
const morningGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] },
];
const nightGates = [
{ id: "North", capacity: 4, queue: [6, 2, 5, 1] },
{ id: "East", capacity: 2, queue: [3, 3, 4, 2] },
{ id: "South", capacity: 5, queue: [2, 1, 2, 3] },
{ id: "West", capacity: 3, queue: [5, 2, 1, 4] },
];
function initializeThroughput(gates) {
const summary = {};
for (const gate of gates) {
summary[gate.id] = 0;
};
return summary;
}
function processGateFlow(gate, tickIndex) {
let currentTickQueue = gate.queue[tickIndex];
let processed = 0;
while (currentTickQueue > 0 && processed < gate.capacity) {
currentTickQueue--;
processed++;
}
return {
processed: processed,
overflow: currentTickQueue
};
}
function rerouteOverflow(gates, currentGate, tickIndex, overflowAmount) {
const currentIndex = gates.indexOf(currentGate);
--fcc-editable-region--
--fcc-editable-region--
}
```

View File

@@ -0,0 +1,117 @@
---
id: 69bac03ae5faf2979a3339ff
title: Step 13
challengeType: 1
dashedName: step-13
---
# --description--
Now that you know which gate to reroute to, you can move the overflow attendees.
Take the `overflowAmount` and add it to the next gates queue at the same `tickIndex`.
Specifically, you must:
- Access the next gate using `nextGateIndex`.
- Access its `queue`.
- Add the `overflowAmount` to the value at position `tickIndex`.
# --hints--
Your `rerouteOverflow` function should add `overflowAmount` to the value at `tickIndex` in the `queue` of the next gate.
```js
const testGates1 = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] }
];
const northGate = testGates1[0];
const originalEastQueue = testGates1[1].queue[0];
rerouteOverflow(testGates1, northGate, 0, 5);
assert.strictEqual(
testGates1[1].queue[0],
originalEastQueue + 5,
"Rerouting from North gate should add overflow to East gate's queue at tickIndex 0"
);
const testGates2 = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] }
];
const westGate = testGates2[3];
const originalNorthQueue = testGates2[0].queue[2];
rerouteOverflow(testGates2, westGate, 2, 3);
assert.strictEqual(
testGates2[0].queue[2],
originalNorthQueue + 3,
"Rerouting from West gate should wrap around and add overflow to North gate's queue at tickIndex 2"
);
const testGates3 = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] }
];
const southGate = testGates3[2];
const originalQueues = testGates3.map(gate => [...gate.queue]);
rerouteOverflow(testGates3, southGate, 1, 2);
assert.deepStrictEqual(testGates3[0].queue, originalQueues[0], "North gate queue should not be modified");
assert.deepStrictEqual(testGates3[1].queue, originalQueues[1], "East gate queue should not be modified");
assert.deepStrictEqual(testGates3[2].queue, originalQueues[2], "South gate queue should not be modified");
assert.strictEqual(testGates3[3].queue[1], originalQueues[3][1] + 2, "Only West gate at tickIndex 1 should be modified");
```
# --seed--
## --seed-contents--
```js
const morningGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] },
];
const nightGates = [
{ id: "North", capacity: 4, queue: [6, 2, 5, 1] },
{ id: "East", capacity: 2, queue: [3, 3, 4, 2] },
{ id: "South", capacity: 5, queue: [2, 1, 2, 3] },
{ id: "West", capacity: 3, queue: [5, 2, 1, 4] },
];
function initializeThroughput(gates) {
const summary = {};
for (const gate of gates) {
summary[gate.id] = 0;
};
return summary;
}
function processGateFlow(gate, tickIndex) {
let currentTickQueue = gate.queue[tickIndex];
let processed = 0;
while (currentTickQueue > 0 && processed < gate.capacity) {
currentTickQueue--;
processed++;
}
return {
processed: processed,
overflow: currentTickQueue
};
}
function rerouteOverflow(gates, currentGate, tickIndex, overflowAmount) {
const currentIndex = gates.indexOf(currentGate);
const nextGateIndex = (currentIndex + 1) % gates.length;
--fcc-editable-region--
--fcc-editable-region--
}
```

View File

@@ -0,0 +1,93 @@
---
id: 69bac047282614c7ef87d370
title: Step 14
challengeType: 1
dashedName: step-14
---
# --description--
To help track how attendees move through the system, log the following message to the console: `overflowAmount + " attendees rerouted to " + gates[nextGateIndex].id`. You can use either string concatenation or template literals.
# --hints--
Your `rerouteOverflow` function should log the following message to the console `overflowAmount + " attendees rerouted to " + gates[nextGateIndex].id`.
```js
const testGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] }
];
const spy = __helpers.spyOn(console, "log");
try {
const northGate = testGates[0];
rerouteOverflow(testGates, northGate, 0, 5);
const expectedCall = ["5 attendees rerouted to East"];
assert.deepEqual(
spy.calls[0],
expectedCall,
"rerouteOverflow should log the overflow amount and next gate's id"
);
} catch (err) {
assert.fail(err);
} finally {
spy.restore();
}
```
# --seed--
## --seed-contents--
```js
const morningGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] },
];
const nightGates = [
{ id: "North", capacity: 4, queue: [6, 2, 5, 1] },
{ id: "East", capacity: 2, queue: [3, 3, 4, 2] },
{ id: "South", capacity: 5, queue: [2, 1, 2, 3] },
{ id: "West", capacity: 3, queue: [5, 2, 1, 4] },
];
function initializeThroughput(gates) {
const summary = {};
for (const gate of gates) {
summary[gate.id] = 0;
};
return summary;
}
function processGateFlow(gate, tickIndex) {
let currentTickQueue = gate.queue[tickIndex];
let processed = 0;
while (currentTickQueue > 0 && processed < gate.capacity) {
currentTickQueue--;
processed++;
}
return {
processed: processed,
overflow: currentTickQueue
};
}
function rerouteOverflow(gates, currentGate, tickIndex, overflowAmount) {
const currentIndex = gates.indexOf(currentGate);
const nextGateIndex = (currentIndex + 1) % gates.length;
gates[nextGateIndex].queue[tickIndex] += overflowAmount;
--fcc-editable-region--
--fcc-editable-region--
}
```

View File

@@ -0,0 +1,87 @@
---
id: 69bac067cd15c4685d07906d
title: Step 15
challengeType: 1
dashedName: step-15
---
# --description--
Now that you have functions to process individual ticks and handle overflow, its time to create a controller function for a single gate. This function will handle all the actions for one gate during a single tick of the simulation.
Create an empty function named `handleGateAtTick` with parameters:
- `gates`: The full array of gate objects.
- `gate`: The current gate being processed.
- `tickIndex`: The current tick index for the simulation.
- `throughputSummary`: An object tracking total processed attendees per gate.
# --hints--
You should create a function named `handleGateAtTick`.
```js
assert.isFunction(handleGateAtTick);
```
Your `handleGateAtTick` function should have parameters `gates`, `gate`, `tickIndex`, and `throughputSummary`.
```js
const regex = __helpers.functionRegex('handleGateAtTick', ['gates', 'gate', 'tickIndex', 'throughputSummary']);
assert.match(__helpers.removeJSComments(handleGateAtTick.toString()), regex);
```
# --seed--
## --seed-contents--
```js
const morningGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] },
];
const nightGates = [
{ id: "North", capacity: 4, queue: [6, 2, 5, 1] },
{ id: "East", capacity: 2, queue: [3, 3, 4, 2] },
{ id: "South", capacity: 5, queue: [2, 1, 2, 3] },
{ id: "West", capacity: 3, queue: [5, 2, 1, 4] },
];
function initializeThroughput(gates) {
const summary = {};
for (const gate of gates) {
summary[gate.id] = 0;
};
return summary;
}
function processGateFlow(gate, tickIndex) {
let currentTickQueue = gate.queue[tickIndex];
let processed = 0;
while (currentTickQueue > 0 && processed < gate.capacity) {
currentTickQueue--;
processed++;
}
return {
processed: processed,
overflow: currentTickQueue
};
}
function rerouteOverflow(gates, currentGate, tickIndex, overflowAmount) {
const currentIndex = gates.indexOf(currentGate);
const nextGateIndex = (currentIndex + 1) % gates.length;
gates[nextGateIndex].queue[tickIndex] += overflowAmount;
console.log(
overflowAmount + " attendees rerouted to " +
gates[nextGateIndex].id
);
}
--fcc-editable-region--
--fcc-editable-region--
```

View File

@@ -0,0 +1,125 @@
---
id: 69bac073b1de8b484bbccc94
title: Step 16
challengeType: 1
dashedName: step-16
---
# --description--
First, log the following message to the console: `"\nProcessing " + gate.id + "..."`.
# --hints--
Your `handleGateAtTick` function should first log the following message to the console, `"\nProcessing " + gate.id + "..."`.
```js
const testGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] }
];
const throughputSummary = { North: 0, East: 0, South: 0, West: 0 };
const spy = __helpers.spyOn(console, "log");
try {
const northGate = testGates[0];
handleGateAtTick(testGates, northGate, 0, throughputSummary);
const expectedCall = ["\nProcessing North..."];
assert.deepEqual(
spy.calls[0],
expectedCall,
"handleGateAtTick should first log the processing message with the gate id"
);
} catch (err) {
assert.fail(err);
} finally {
spy.restore();
}
```
Your `handleGateAtTick` function should log the correct gate ID in the message.
```js
const testGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] }
];
const throughputSummary = { North: 0, East: 0, South: 0, West: 0 };
const spy = __helpers.spyOn(console, "log");
try {
const southGate = testGates[2];
handleGateAtTick(testGates, southGate, 1, throughputSummary);
const expectedCall = ["\nProcessing South..."];
assert.deepEqual(
spy.calls[0],
expectedCall,
"handleGateAtTick should log the processing message with the correct gate id"
);
} catch (err) {
assert.fail(err);
} finally {
spy.restore();
}
```
# --seed--
## --seed-contents--
```js
const morningGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] },
];
const nightGates = [
{ id: "North", capacity: 4, queue: [6, 2, 5, 1] },
{ id: "East", capacity: 2, queue: [3, 3, 4, 2] },
{ id: "South", capacity: 5, queue: [2, 1, 2, 3] },
{ id: "West", capacity: 3, queue: [5, 2, 1, 4] },
];
function initializeThroughput(gates) {
const summary = {};
for (const gate of gates) {
summary[gate.id] = 0;
};
return summary;
}
function processGateFlow(gate, tickIndex) {
let currentTickQueue = gate.queue[tickIndex];
let processed = 0;
while (currentTickQueue > 0 && processed < gate.capacity) {
currentTickQueue--;
processed++;
}
return {
processed: processed,
overflow: currentTickQueue
};
}
function rerouteOverflow(gates, currentGate, tickIndex, overflowAmount) {
const currentIndex = gates.indexOf(currentGate);
const nextGateIndex = (currentIndex + 1) % gates.length;
gates[nextGateIndex].queue[tickIndex] += overflowAmount;
console.log(
" " + overflowAmount + " attendees rerouted to " +
gates[nextGateIndex].id
);
}
function handleGateAtTick(gates, gate, tickIndex, throughputSummary) {
--fcc-editable-region--
--fcc-editable-region--
}
```

View File

@@ -0,0 +1,139 @@
---
id: 69bac08105bec16db267dcbf
title: Step 17
challengeType: 1
dashedName: step-17
---
# --description--
Next, log the following message to the console: `gate.queue[tickIndex] + " attendees arriving."`.
# --hints--
Your `handleGateAtTick` function should log the following message to the console: `gate.queue[tickIndex] + " attendees arriving."`.
```js
const testGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] }
];
const throughputSummary = { North: 0, East: 0, South: 0, West: 0 };
const spy = __helpers.spyOn(console, "log");
try {
const northGate = testGates[0];
handleGateAtTick(testGates, northGate, 0, throughputSummary);
const expectedFirstCall = ["\nProcessing North..."];
const expectedSecondCall = ["3 attendees arriving."];
assert.deepEqual(
spy.calls[0],
expectedFirstCall,
"First log should be the processing message"
);
assert.deepEqual(
spy.calls[1],
expectedSecondCall,
"Second log should show the number of attendees arriving"
);
} catch (err) {
assert.fail(err);
} finally {
spy.restore();
}
```
Your `handleGateAtTick` function should log the correct number of attendees based on the gate's queue at the given tickIndex.
```js
const testGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] }
];
const throughputSummary = { North: 0, East: 0, South: 0, West: 0 };
const spy = __helpers.spyOn(console, "log");
try {
const eastGate = testGates[1];
handleGateAtTick(testGates, eastGate, 3, throughputSummary);
const expectedFirstCall = ["\nProcessing East..."];
const expectedSecondCall = ["5 attendees arriving."];
assert.deepEqual(
spy.calls[0],
expectedFirstCall,
"First log should be the processing message with the correct gate"
);
assert.deepEqual(
spy.calls[1],
expectedSecondCall,
"Second log should show the correct number of attendees from queue at tickIndex 3"
);
} catch (err) {
assert.fail(err);
} finally {
spy.restore();
}
```
# --seed--
## --seed-contents--
```js
const morningGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] },
];
const nightGates = [
{ id: "North", capacity: 4, queue: [6, 2, 5, 1] },
{ id: "East", capacity: 2, queue: [3, 3, 4, 2] },
{ id: "South", capacity: 5, queue: [2, 1, 2, 3] },
{ id: "West", capacity: 3, queue: [5, 2, 1, 4] },
];
function initializeThroughput(gates) {
const summary = {};
for (const gate of gates) {
summary[gate.id] = 0;
};
return summary;
}
function processGateFlow(gate, tickIndex) {
let currentTickQueue = gate.queue[tickIndex];
let processed = 0;
while (currentTickQueue > 0 && processed < gate.capacity) {
currentTickQueue--;
processed++;
}
return {
processed: processed,
overflow: currentTickQueue
};
}
function rerouteOverflow(gates, currentGate, tickIndex, overflowAmount) {
const currentIndex = gates.indexOf(currentGate);
const nextGateIndex = (currentIndex + 1) % gates.length;
gates[nextGateIndex].queue[tickIndex] += overflowAmount;
console.log(
overflowAmount + " attendees rerouted to " +
gates[nextGateIndex].id
);
}
function handleGateAtTick(gates, gate, tickIndex, throughputSummary) {
console.log("\nProcessing " + gate.id + "...");
--fcc-editable-region--
--fcc-editable-region--
}
```

View File

@@ -0,0 +1,123 @@
---
id: 69bac0a011a9c1f735d306c2
title: Step 18
challengeType: 1
dashedName: step-18
---
# --description--
Process the input gate for the current tick by calling `processGateFlow()` with `gate` and `tickIndex` and assigning the result to a variable named `result`.
# --hints--
Your `handleGateAtTick` function should call the `processGateFlow()` method.
```js
const testGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] }
];
const throughputSummary = { North: 0, East: 0, South: 0, West: 0 };
const originalProcessGateFlow = processGateFlow;
let called = false;
try {
processGateFlow = function (...args) {
called = true;
return originalProcessGateFlow(...args);
};
const northGate = testGates[0];
handleGateAtTick(testGates, northGate, 0, throughputSummary);
assert.isTrue(
called,
"handleGateAtTick should call processGateFlow()"
);
} catch (err) {
assert.fail(err);
} finally {
processGateFlow = originalProcessGateFlow;
}
```
You should call `processGateFlow()` with `gate` and `tickIndex` and assign the result to a variable named `result`.
```js
const rawFuncStr = __helpers.removeJSComments(handleGateAtTick.toString());
assert.match(
rawFuncStr,
/(var|const|let)\s+result/,
"You must have at least one space between the declaration keyword (let/const) and 'result'."
);
const cleaned = __helpers.removeWhiteSpace(rawFuncStr);
const solution = /(var|const|let)result=processGateFlow\(gate,tickIndex\);?}$/;
assert(
solution.test(cleaned),
"Inside your `handleGateAtTick` function, call `processGateFlow()` with `gate` and `tickIndex` and assign the result to a variable named `result`."
);
```
# --seed--
## --seed-contents--
```js
const morningGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] },
];
const nightGates = [
{ id: "North", capacity: 4, queue: [6, 2, 5, 1] },
{ id: "East", capacity: 2, queue: [3, 3, 4, 2] },
{ id: "South", capacity: 5, queue: [2, 1, 2, 3] },
{ id: "West", capacity: 3, queue: [5, 2, 1, 4] },
];
function initializeThroughput(gates) {
const summary = {};
for (const gate of gates) {
summary[gate.id] = 0;
};
return summary;
}
function processGateFlow(gate, tickIndex) {
let currentTickQueue = gate.queue[tickIndex];
let processed = 0;
while (currentTickQueue > 0 && processed < gate.capacity) {
currentTickQueue--;
processed++;
}
return {
processed: processed,
overflow: currentTickQueue
};
}
function rerouteOverflow(gates, currentGate, tickIndex, overflowAmount) {
const currentIndex = gates.indexOf(currentGate);
const nextGateIndex = (currentIndex + 1) % gates.length;
gates[nextGateIndex].queue[tickIndex] += overflowAmount;
console.log(
overflowAmount + " attendees rerouted to " +
gates[nextGateIndex].id
);
}
function handleGateAtTick(gates, gate, tickIndex, throughputSummary) {
console.log("\nProcessing " + gate.id + "...");
console.log(
gate.queue[tickIndex] + " attendees arriving."
);
--fcc-editable-region--
--fcc-editable-region--
}
```

View File

@@ -0,0 +1,171 @@
---
id: 69bac0d5a0b16122a2a938a4
title: Step 19
challengeType: 1
dashedName: step-19
---
# --description--
Next, update the input `throughputSummary` object to reflect how many attendees were successfully processed by this gate at the current tick. Specifically, take the value of `processed` in `result` and add it to the element in `throughputSummary` at index `gate.id`.
This step ensures that the throughput summary accumulates attendees over multiple ticks.
# --hints--
You should add `result.processed` to `throughputSummary[gate.id]`.
```js
const testGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] }
];
const throughputSummary = { North: 0, East: 0, South: 0, West: 0 };
const console_log = console.log;
console.log = () => {};
try {
const northGate = testGates[0];
handleGateAtTick(testGates, northGate, 0, throughputSummary);
assert.strictEqual(
throughputSummary["North"],
3,
"North gate should have 3 attendees processed at tick 0 (capacity 5, queue 3)"
);
} finally {
console.log = console_log;
}
```
Your `handleGateAtTick` function should accumulate processed attendees over multiple ticks.
```js
const testGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] }
];
const throughputSummary = { North: 0, East: 0, South: 0, West: 0 };
const console_log = console.log;
console.log = () => {};
try {
const northGate = testGates[0];
handleGateAtTick(testGates, northGate, 0, throughputSummary);
handleGateAtTick(testGates, northGate, 1, throughputSummary);
assert.strictEqual(
throughputSummary["North"],
8,
"North gate should accumulate processed attendees: 3 from tick 0 + 5 from tick 1"
);
} finally {
console.log = console_log;
}
```
Your `handleGateAtTick` function should only update the throughput for the specific gate being processed.
```js
const testGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] }
];
const throughputSummary = { North: 0, East: 0, South: 0, West: 0 };
const console_log = console.log;
console.log = () => {};
try {
const westGate = testGates[3];
handleGateAtTick(testGates, westGate, 0, throughputSummary);
assert.strictEqual(
throughputSummary["West"],
2,
"West gate should have 2 attendees processed (capacity 2, queue 4)"
);
assert.strictEqual(
throughputSummary["North"],
0,
"North gate should remain unmodified"
);
assert.strictEqual(
throughputSummary["East"],
0,
"East gate should remain unmodified"
);
assert.strictEqual(
throughputSummary["South"],
0,
"South gate should remain unmodified"
);
} finally {
console.log = console_log;
}
```
# --seed--
## --seed-contents--
```js
const morningGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] },
];
const nightGates = [
{ id: "North", capacity: 4, queue: [6, 2, 5, 1] },
{ id: "East", capacity: 2, queue: [3, 3, 4, 2] },
{ id: "South", capacity: 5, queue: [2, 1, 2, 3] },
{ id: "West", capacity: 3, queue: [5, 2, 1, 4] },
];
function initializeThroughput(gates) {
const summary = {};
for (const gate of gates) {
summary[gate.id] = 0;
};
return summary;
}
function processGateFlow(gate, tickIndex) {
let currentTickQueue = gate.queue[tickIndex];
let processed = 0;
while (currentTickQueue > 0 && processed < gate.capacity) {
currentTickQueue--;
processed++;
}
return {
processed: processed,
overflow: currentTickQueue
};
}
function rerouteOverflow(gates, currentGate, tickIndex, overflowAmount) {
const currentIndex = gates.indexOf(currentGate);
const nextGateIndex = (currentIndex + 1) % gates.length;
gates[nextGateIndex].queue[tickIndex] += overflowAmount;
console.log(
overflowAmount + " attendees rerouted to " +
gates[nextGateIndex].id
);
}
function handleGateAtTick(gates, gate, tickIndex, throughputSummary) {
console.log("\nProcessing " + gate.id + "...");
console.log(
gate.queue[tickIndex] + " attendees arriving."
);
const result = processGateFlow(gate, tickIndex);
--fcc-editable-region--
--fcc-editable-region--
}
```

View File

@@ -0,0 +1,160 @@
---
id: 69bac0e7112d02531998dbf0
title: Step 20
challengeType: 1
dashedName: step-20
---
# --description--
The final task in your `handleGateAtTick` function is to handle any overflow for the current tick.
If any overflow exists (`result.overflow > 0`), you should:
- Log the following message `"Overflow of " + result.overflow + " attendees. Rerouting..."`.
- Reroute the overflow by calling your `rerouteOverflow()` function with `gates`, `gate`, `tickIndex`, and `result.overflow`.
# --hints--
If any overflow exists (`result.overflow > 0`), you should first log the message `"Overflow of " + result.overflow + " attendees. Rerouting..."`.
```js
const testGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] }
];
const throughputSummary = { North: 0, East: 0, South: 0, West: 0 };
const spy = __helpers.spyOn(console, "log");
try {
const westGate = testGates[3];
handleGateAtTick(testGates, westGate, 0, throughputSummary);
const overflowMessage = spy.calls.find(call => call[0].includes("Overflow of"));
assert.isTrue(
typeof overflowMessage !== "undefined",
"handleGateAtTick should log an overflow message when overflow exists"
);
assert.match(
overflowMessage[0],
/Overflow of \d+ attendees\. Rerouting\.\.\.$/,
"Overflow message should match the format 'Overflow of X attendees. Rerouting...'"
);
} catch (err) {
assert.fail(err);
} finally {
spy.restore();
}
```
If any overflow exists (`result.overflow > 0`), you should reroute the overflow by calling `rerouteOverflow()` with `gates`, `gate`, `tickIndex`, and `result.overflow`.
```js
const testGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] }
];
const throughputSummary = { North: 0, East: 0, South: 0, West: 0 };
const originalRerouteOverflow = rerouteOverflow;
let called = false;
let callArgs = null;
try {
rerouteOverflow = function (...args) {
called = true;
callArgs = args;
return originalRerouteOverflow(...args);
};
const consoleSpy = __helpers.spyOn(console, "log");
try {
const westGate = testGates[3];
const originalNorthQueue = testGates[0].queue[0];
handleGateAtTick(testGates, westGate, 0, throughputSummary);
assert.isTrue(
called,
"handleGateAtTick should call rerouteOverflow() when overflow exists"
);
assert.deepEqual(
callArgs,
[testGates, westGate, 0, 2],
"rerouteOverflow should be called with gates, gate, tickIndex, and overflow amount"
);
assert.strictEqual(
testGates[0].queue[0],
originalNorthQueue + 2,
"Overflow from West should be rerouted to North gate's queue (next gate with wrap-around)"
);
} finally {
consoleSpy.restore();
}
} catch (err) {
assert.fail(err);
} finally {
rerouteOverflow = originalRerouteOverflow;
}
```
# --seed--
## --seed-contents--
```js
const morningGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] },
];
const nightGates = [
{ id: "North", capacity: 4, queue: [6, 2, 5, 1] },
{ id: "East", capacity: 2, queue: [3, 3, 4, 2] },
{ id: "South", capacity: 5, queue: [2, 1, 2, 3] },
{ id: "West", capacity: 3, queue: [5, 2, 1, 4] },
];
function initializeThroughput(gates) {
const summary = {};
for (const gate of gates) {
summary[gate.id] = 0;
};
return summary;
}
function processGateFlow(gate, tickIndex) {
let currentTickQueue = gate.queue[tickIndex];
let processed = 0;
while (currentTickQueue > 0 && processed < gate.capacity) {
currentTickQueue--;
processed++;
}
return {
processed: processed,
overflow: currentTickQueue
};
}
function rerouteOverflow(gates, currentGate, tickIndex, overflowAmount) {
const currentIndex = gates.indexOf(currentGate);
const nextGateIndex = (currentIndex + 1) % gates.length;
gates[nextGateIndex].queue[tickIndex] += overflowAmount;
console.log(
overflowAmount + " attendees rerouted to " +
gates[nextGateIndex].id
);
}
function handleGateAtTick(gates, gate, tickIndex, throughputSummary) {
console.log("\nProcessing " + gate.id + "...");
console.log(
gate.queue[tickIndex] + " attendees arriving."
);
const result = processGateFlow(gate, tickIndex);
throughputSummary[gate.id] += result.processed;
--fcc-editable-region--
--fcc-editable-region--
}
```

View File

@@ -0,0 +1,96 @@
---
id: 69bac0f9659af01091c5967d
title: Step 21
challengeType: 1
dashedName: step-21
---
# --description--
It will be helpful to have a function for displaying a summary of throughput during a simulation. Create an empty function named `printSummary` with a parameter `summary`.
# --hints--
You should create a function named `printSummary`.
```js
assert.isFunction(printSummary);
```
Your `printSummary` function should have a parameter `summary`.
```js
const regex = __helpers.functionRegex('printSummary', ['summary']);
assert.match(__helpers.removeJSComments(printSummary.toString()), regex);
```
# --seed--
## --seed-contents--
```js
const morningGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] },
];
const nightGates = [
{ id: "North", capacity: 4, queue: [6, 2, 5, 1] },
{ id: "East", capacity: 2, queue: [3, 3, 4, 2] },
{ id: "South", capacity: 5, queue: [2, 1, 2, 3] },
{ id: "West", capacity: 3, queue: [5, 2, 1, 4] },
];
function initializeThroughput(gates) {
const summary = {};
for (const gate of gates) {
summary[gate.id] = 0;
};
return summary;
}
function processGateFlow(gate, tickIndex) {
let currentTickQueue = gate.queue[tickIndex];
let processed = 0;
while (currentTickQueue > 0 && processed < gate.capacity) {
currentTickQueue--;
processed++;
}
return {
processed: processed,
overflow: currentTickQueue
};
}
function rerouteOverflow(gates, currentGate, tickIndex, overflowAmount) {
const currentIndex = gates.indexOf(currentGate);
const nextGateIndex = (currentIndex + 1) % gates.length;
gates[nextGateIndex].queue[tickIndex] += overflowAmount;
console.log(
overflowAmount + " attendees rerouted to " +
gates[nextGateIndex].id
);
}
function handleGateAtTick(gates, gate, tickIndex, throughputSummary) {
console.log("\nProcessing " + gate.id + "...");
console.log(
gate.queue[tickIndex] + " attendees arriving."
);
const result = processGateFlow(gate, tickIndex);
throughputSummary[gate.id] += result.processed;
if (result.overflow > 0) {
console.log(
"Overflow of " + result.overflow +
" attendees. Rerouting..."
);
rerouteOverflow(gates, gate, tickIndex, result.overflow);
}
}
--fcc-editable-region--
--fcc-editable-region--
```

View File

@@ -0,0 +1,106 @@
---
id: 69bac11611f4c349e8e666ec
title: Step 22
challengeType: 1
dashedName: step-22
---
# --description--
First, log the following message to the console `"\nThroughput Summary"`.
# --hints--
Your `printSummary` function should first log the following message to the console, `"\nThroughput Summary"`.
```js
const testSummary = { North: 5, East: 3, South: 4, West: 2 };
const spy = __helpers.spyOn(console, "log");
try {
printSummary(testSummary);
const expectedCall = ["\nThroughput Summary"];
assert.deepEqual(
spy.calls[0],
expectedCall,
"printSummary should log the throughput summary header"
);
} catch (err) {
assert.fail(err);
} finally {
spy.restore();
}
```
# --seed--
## --seed-contents--
```js
const morningGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] },
];
const nightGates = [
{ id: "North", capacity: 4, queue: [6, 2, 5, 1] },
{ id: "East", capacity: 2, queue: [3, 3, 4, 2] },
{ id: "South", capacity: 5, queue: [2, 1, 2, 3] },
{ id: "West", capacity: 3, queue: [5, 2, 1, 4] },
];
function initializeThroughput(gates) {
const summary = {};
for (const gate of gates) {
summary[gate.id] = 0;
};
return summary;
}
function processGateFlow(gate, tickIndex) {
let currentTickQueue = gate.queue[tickIndex];
let processed = 0;
while (currentTickQueue > 0 && processed < gate.capacity) {
currentTickQueue--;
processed++;
}
return {
processed: processed,
overflow: currentTickQueue
};
}
function rerouteOverflow(gates, currentGate, tickIndex, overflowAmount) {
const currentIndex = gates.indexOf(currentGate);
const nextGateIndex = (currentIndex + 1) % gates.length;
gates[nextGateIndex].queue[tickIndex] += overflowAmount;
console.log(
overflowAmount + " attendees rerouted to " +
gates[nextGateIndex].id
);
}
function handleGateAtTick(gates, gate, tickIndex, throughputSummary) {
console.log("\nProcessing " + gate.id + "...");
console.log(
gate.queue[tickIndex] + " attendees arriving."
);
const result = processGateFlow(gate, tickIndex);
throughputSummary[gate.id] += result.processed;
if (result.overflow > 0) {
console.log(
"Overflow of " + result.overflow +
" attendees. Rerouting..."
);
rerouteOverflow(gates, gate, tickIndex, result.overflow);
}
}
function printSummary(summary) {
--fcc-editable-region--
--fcc-editable-region--
}
```

View File

@@ -0,0 +1,147 @@
---
id: 69bac12483f656898154f969
title: Step 23
challengeType: 1
dashedName: step-23
---
# --description--
Use a `for...in` loop to iterate through every gate in the input `summary` object and log the total attendees processed.
For each gate, log a message in this format: `gate + ": " + summary[gate] + " attendees processed"`.
As an example, for an input `summary` object defined as `{ North: 5, East: 3, South: 4, West: 2 }`, you should log:
```js
North: 5 attendees processed
East: 3 attendees processed
South: 4 attendees processed
West: 2 attendees processed
```
# --hints--
You should loop through every element in the `summary` object and log the following message once per element: `element + ": " + summary[element] + " attendees processed`.
```js
const testSummary = { North: 12, East: 8, South: 5, West: 4 };
const spy = __helpers.spyOn(console, "log");
try {
printSummary(testSummary);
assert.lengthOf(
spy.calls,
5,
"Should log 1 header message + 4 gate messages"
);
assert.deepEqual(
spy.calls[0],
["\nThroughput Summary"],
"First log should be the header"
);
assert.match(
spy.calls[1][0],
/North: 12 attendees processed/,
"Should log throughput for North gate"
);
assert.match(
spy.calls[2][0],
/East: 8 attendees processed/,
"Should log throughput for East gate"
);
assert.match(
spy.calls[3][0],
/South: 5 attendees processed/,
"Should log throughput for South gate"
);
assert.match(
spy.calls[4][0],
/West: 4 attendees processed/,
"Should log throughput for West gate"
);
} catch (err) {
assert.fail(err);
} finally {
spy.restore();
}
```
# --seed--
## --seed-contents--
```js
const morningGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] },
];
const nightGates = [
{ id: "North", capacity: 4, queue: [6, 2, 5, 1] },
{ id: "East", capacity: 2, queue: [3, 3, 4, 2] },
{ id: "South", capacity: 5, queue: [2, 1, 2, 3] },
{ id: "West", capacity: 3, queue: [5, 2, 1, 4] },
];
function initializeThroughput(gates) {
const summary = {};
for (const gate of gates) {
summary[gate.id] = 0;
};
return summary;
}
function processGateFlow(gate, tickIndex) {
let currentTickQueue = gate.queue[tickIndex];
let processed = 0;
while (currentTickQueue > 0 && processed < gate.capacity) {
currentTickQueue--;
processed++;
}
return {
processed: processed,
overflow: currentTickQueue
};
}
function rerouteOverflow(gates, currentGate, tickIndex, overflowAmount) {
const currentIndex = gates.indexOf(currentGate);
const nextGateIndex = (currentIndex + 1) % gates.length;
gates[nextGateIndex].queue[tickIndex] += overflowAmount;
console.log(
overflowAmount + " attendees rerouted to " +
gates[nextGateIndex].id
);
}
function handleGateAtTick(gates, gate, tickIndex, throughputSummary) {
console.log("\nProcessing " + gate.id + "...");
console.log(
gate.queue[tickIndex] + " attendees arriving."
);
const result = processGateFlow(gate, tickIndex);
throughputSummary[gate.id] += result.processed;
if (result.overflow > 0) {
console.log(
"Overflow of " + result.overflow +
" attendees. Rerouting..."
);
rerouteOverflow(gates, gate, tickIndex, result.overflow);
}
}
function printSummary(summary) {
console.log("\nThroughput Summary");
--fcc-editable-region--
--fcc-editable-region--
}
```

View File

@@ -0,0 +1,106 @@
---
id: 69bac146b5f30209b4179af1
title: Step 24
challengeType: 1
dashedName: step-24
---
# --description--
Now you can build a function for simulating the festival. Create an empty function named `simulateFestival` with parameters `gates` and `timeBlock`.
# --hints--
You should create a function named `simulateFestival`.
```js
assert.isFunction(simulateFestival);
```
Your `simulateFestival` function should have parameters `gates` and `timeBlock`.
```js
const regex = __helpers.functionRegex('simulateFestival', ['gates', 'timeBlock']);
assert.match(__helpers.removeJSComments(simulateFestival.toString()), regex);
```
# --seed--
## --seed-contents--
```js
const morningGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] },
];
const nightGates = [
{ id: "North", capacity: 4, queue: [6, 2, 5, 1] },
{ id: "East", capacity: 2, queue: [3, 3, 4, 2] },
{ id: "South", capacity: 5, queue: [2, 1, 2, 3] },
{ id: "West", capacity: 3, queue: [5, 2, 1, 4] },
];
function initializeThroughput(gates) {
const summary = {};
for (const gate of gates) {
summary[gate.id] = 0;
};
return summary;
}
function processGateFlow(gate, tickIndex) {
let currentTickQueue = gate.queue[tickIndex];
let processed = 0;
while (currentTickQueue > 0 && processed < gate.capacity) {
currentTickQueue--;
processed++;
}
return {
processed: processed,
overflow: currentTickQueue
};
}
function rerouteOverflow(gates, currentGate, tickIndex, overflowAmount) {
const currentIndex = gates.indexOf(currentGate);
const nextGateIndex = (currentIndex + 1) % gates.length;
gates[nextGateIndex].queue[tickIndex] += overflowAmount;
console.log(
overflowAmount + " attendees rerouted to " +
gates[nextGateIndex].id
);
}
function handleGateAtTick(gates, gate, tickIndex, throughputSummary) {
console.log("\nProcessing " + gate.id + "...");
console.log(
gate.queue[tickIndex] + " attendees arriving."
);
const result = processGateFlow(gate, tickIndex);
throughputSummary[gate.id] += result.processed;
if (result.overflow > 0) {
console.log(
"Overflow of " + result.overflow +
" attendees. Rerouting..."
);
rerouteOverflow(gates, gate, tickIndex, result.overflow);
}
}
function printSummary(summary) {
console.log("\nThroughput Summary");
for (const gateId in summary) {
console.log(
gateId + ": " + summary[gateId] +
" attendees processed"
);
}
}
--fcc-editable-region--
--fcc-editable-region--
```

View File

@@ -0,0 +1,155 @@
---
id: 69bac15062ac8a348b84fe46
title: Step 25
challengeType: 1
dashedName: step-25
---
# --description--
First, log the following message to the console: `"\n" + timeBlock + " Simulation"`.
# --hints--
Your `simulateFestival` function should first log the message `"\n" + timeBlock + " Simulation"`.
```js
const testGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] }
];
const spy = __helpers.spyOn(console, "log");
try {
simulateFestival(testGates, "Morning");
const expectedCall = ["\nMorning Simulation"];
assert.deepEqual(
spy.calls[0],
expectedCall,
"simulateFestival should log the simulation header with the timeBlock"
);
} catch (err) {
assert.fail(err);
} finally {
spy.restore();
}
```
Your `simulateFestival` function should log the correct time block in the message.
```js
const testGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] }
];
const spy = __helpers.spyOn(console, "log");
try {
simulateFestival(testGates, "Night");
const expectedCall = ["\nNight Simulation"];
assert.deepEqual(
spy.calls[0],
expectedCall,
"simulateFestival should correctly embed the timeBlock parameter in the message"
);
} catch (err) {
assert.fail(err);
} finally {
spy.restore();
}
```
# --seed--
## --seed-contents--
```js
const morningGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] },
];
const nightGates = [
{ id: "North", capacity: 4, queue: [6, 2, 5, 1] },
{ id: "East", capacity: 2, queue: [3, 3, 4, 2] },
{ id: "South", capacity: 5, queue: [2, 1, 2, 3] },
{ id: "West", capacity: 3, queue: [5, 2, 1, 4] },
];
function initializeThroughput(gates) {
const summary = {};
for (const gate of gates) {
summary[gate.id] = 0;
};
return summary;
}
function processGateFlow(gate, tickIndex) {
let currentTickQueue = gate.queue[tickIndex];
let processed = 0;
while (currentTickQueue > 0 && processed < gate.capacity) {
currentTickQueue--;
processed++;
}
return {
processed: processed,
overflow: currentTickQueue
};
}
function rerouteOverflow(gates, currentGate, tickIndex, overflowAmount) {
const currentIndex = gates.indexOf(currentGate);
const nextGateIndex = (currentIndex + 1) % gates.length;
gates[nextGateIndex].queue[tickIndex] += overflowAmount;
console.log(
overflowAmount + " attendees rerouted to " +
gates[nextGateIndex].id
);
}
function handleGateAtTick(gates, gate, tickIndex, throughputSummary) {
console.log("\nProcessing " + gate.id + "...");
console.log(
gate.queue[tickIndex] + " attendees arriving."
);
const result = processGateFlow(gate, tickIndex);
throughputSummary[gate.id] += result.processed;
if (result.overflow > 0) {
console.log(
"Overflow of " + result.overflow +
" attendees. Rerouting..."
);
rerouteOverflow(gates, gate, tickIndex, result.overflow);
}
}
function printSummary(summary) {
console.log("\nThroughput Summary");
for (const gateId in summary) {
console.log(
gateId + ": " + summary[gateId] +
" attendees processed"
);
}
}
function simulateFestival(gates, timeBlock) {
--fcc-editable-region--
--fcc-editable-region--
}
```

View File

@@ -0,0 +1,162 @@
---
id: 69bac17a4c53a3812b595eb9
title: Step 26
challengeType: 1
dashedName: step-26
---
# --description--
Before starting the simulation, you need an object to track how many attendees each gate processes over all ticks. Call `initializeThroughput()` with `gates` and assign the result to a variable named `throughputSummary`.
# --hints--
You should call `initializeThroughput()` with `gates` and assign the result to a variable named `throughputSummary`.
```js
const rawFuncStr = __helpers.removeJSComments(simulateFestival.toString());
assert.match(
rawFuncStr,
/(var|const|let)\s+throughputSummary/,
"You must have at least one space between the declaration keyword (let/const) and 'throughputSummary'."
);
const cleaned = __helpers.removeWhiteSpace(rawFuncStr);
const solution = /(var|const|let)throughputSummary=initializeThroughput\(gates\);?}$/;
assert(
solution.test(cleaned),
"Inside your `simulateFestival` function, call `initializeThroughput()` with `gates` and assign the result to a variable named `throughputSummary`."
);
```
Your `simulateFestival` function should call the `initializeThroughput()` function with `gates`.
```js
const testGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] }
];
const originalInitializeThroughput = initializeThroughput;
let called = false;
let callArgs = null;
try {
initializeThroughput = function (...args) {
called = true;
callArgs = args;
return originalInitializeThroughput(...args);
};
const consoleSpy = __helpers.spyOn(console, "log");
try {
simulateFestival(testGates, "Morning");
assert.isTrue(
called,
"simulateFestival should call initializeThroughput()"
);
assert.deepEqual(
callArgs,
[testGates],
"initializeThroughput should be called with gates parameter"
);
} finally {
consoleSpy.restore();
}
} catch (err) {
assert.fail(err);
} finally {
initializeThroughput = originalInitializeThroughput;
}
```
# --seed--
## --seed-contents--
```js
const morningGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] },
];
const nightGates = [
{ id: "North", capacity: 4, queue: [6, 2, 5, 1] },
{ id: "East", capacity: 2, queue: [3, 3, 4, 2] },
{ id: "South", capacity: 5, queue: [2, 1, 2, 3] },
{ id: "West", capacity: 3, queue: [5, 2, 1, 4] },
];
function initializeThroughput(gates) {
const summary = {};
for (const gate of gates) {
summary[gate.id] = 0;
};
return summary;
}
function processGateFlow(gate, tickIndex) {
let currentTickQueue = gate.queue[tickIndex];
let processed = 0;
while (currentTickQueue > 0 && processed < gate.capacity) {
currentTickQueue--;
processed++;
}
return {
processed: processed,
overflow: currentTickQueue
};
}
function rerouteOverflow(gates, currentGate, tickIndex, overflowAmount) {
const currentIndex = gates.indexOf(currentGate);
const nextGateIndex = (currentIndex + 1) % gates.length;
gates[nextGateIndex].queue[tickIndex] += overflowAmount;
console.log(
overflowAmount + " attendees rerouted to " +
gates[nextGateIndex].id
);
}
function handleGateAtTick(gates, gate, tickIndex, throughputSummary) {
console.log("\nProcessing " + gate.id + "...");
console.log(
gate.queue[tickIndex] + " attendees arriving."
);
const result = processGateFlow(gate, tickIndex);
throughputSummary[gate.id] += result.processed;
if (result.overflow > 0) {
console.log(
"Overflow of " + result.overflow +
" attendees. Rerouting..."
);
rerouteOverflow(gates, gate, tickIndex, result.overflow);
}
}
function printSummary(summary) {
console.log("\nThroughput Summary");
for (const gateId in summary) {
console.log(
gateId + ": " + summary[gateId] +
" attendees processed"
);
}
}
function simulateFestival(gates, timeBlock) {
console.log("\n" + timeBlock + " Simulation");
--fcc-editable-region--
--fcc-editable-region--
}
```

View File

@@ -0,0 +1,123 @@
---
id: 69bac18fe3729f6761344365
title: Step 27
challengeType: 1
dashedName: step-27
---
# --description--
You need to know how many ticks the simulation should run. Recall that:
- Each gate has a `queue` array that shows how many attendees arrive at each tick.
- Since all gates have the same number of ticks, you can simply use the length of the first gates queue.
Create a variable named `maxTicks` and assign it the value of `gates[0].queue.length`.
This value will be used to control your simulation loop, ensuring each tick is processed for all gates.
# --hints--
You should create a variable named `maxTicks` and assign it the value of `gates[0].queue.length`.
```js
const rawFuncStr = __helpers.removeJSComments(simulateFestival.toString());
assert.match(
rawFuncStr,
/(var|const|let)\s+maxTicks/,
"You must have at least one space between the declaration keyword (let/const) and 'maxTicks'."
);
const cleaned = __helpers.removeWhiteSpace(rawFuncStr);
const solution = /(var|const|let)maxTicks=gates\[0\]\.queue\.length;?}$/;
assert(
solution.test(cleaned),
"Inside your `simulateFestival` function, create a variable named `maxTicks` and assign it the value of `gates[0].queue.length`."
);
```
# --seed--
## --seed-contents--
```js
const morningGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] },
];
const nightGates = [
{ id: "North", capacity: 4, queue: [6, 2, 5, 1] },
{ id: "East", capacity: 2, queue: [3, 3, 4, 2] },
{ id: "South", capacity: 5, queue: [2, 1, 2, 3] },
{ id: "West", capacity: 3, queue: [5, 2, 1, 4] },
];
function initializeThroughput(gates) {
const summary = {};
for (const gate of gates) {
summary[gate.id] = 0;
};
return summary;
}
function processGateFlow(gate, tickIndex) {
let currentTickQueue = gate.queue[tickIndex];
let processed = 0;
while (currentTickQueue > 0 && processed < gate.capacity) {
currentTickQueue--;
processed++;
}
return {
processed: processed,
overflow: currentTickQueue
};
}
function rerouteOverflow(gates, currentGate, tickIndex, overflowAmount) {
const currentIndex = gates.indexOf(currentGate);
const nextGateIndex = (currentIndex + 1) % gates.length;
gates[nextGateIndex].queue[tickIndex] += overflowAmount;
console.log(
overflowAmount + " attendees rerouted to " +
gates[nextGateIndex].id
);
}
function handleGateAtTick(gates, gate, tickIndex, throughputSummary) {
console.log("\nProcessing " + gate.id + "...");
console.log(
gate.queue[tickIndex] + " attendees arriving."
);
const result = processGateFlow(gate, tickIndex);
throughputSummary[gate.id] += result.processed;
if (result.overflow > 0) {
console.log(
"Overflow of " + result.overflow +
" attendees. Rerouting..."
);
rerouteOverflow(gates, gate, tickIndex, result.overflow);
}
}
function printSummary(summary) {
console.log("\nThroughput Summary");
for (const gateId in summary) {
console.log(
gateId + ": " + summary[gateId] +
" attendees processed"
);
}
}
function simulateFestival(gates, timeBlock) {
console.log("\n" + timeBlock + " Simulation");
const throughputSummary = initializeThroughput(gates);
--fcc-editable-region--
--fcc-editable-region--
}
```

View File

@@ -0,0 +1,119 @@
---
id: 69bac1a094d01d84ae4c9e75
title: Step 28
challengeType: 1
dashedName: step-28
---
# --description--
To keep track of which tick is currently being processed during the simulation, create a variable named `tickIndex` and assign it an initial value of `0`.
This variable will be used to loop through all ticks in your simulation and ensure each gate is processed in the correct order.
# --hints--
You should create a variable named `tickIndex` and assign it a value of `0`.
```js
const rawFuncStr = __helpers.removeJSComments(simulateFestival.toString());
assert.match(
rawFuncStr,
/(var|const|let)\s+tickIndex/,
"You must have at least one space between the declaration keyword (let/const) and 'tickIndex'."
);
const cleaned = __helpers.removeWhiteSpace(rawFuncStr);
const solution = /(var|const|let)tickIndex=0;?}$/;
assert(
solution.test(cleaned),
"Inside your `simulateFestival` function, create a variable named `tickIndex` and assign it a value of `0`."
);
```
# --seed--
## --seed-contents--
```js
const morningGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] },
];
const nightGates = [
{ id: "North", capacity: 4, queue: [6, 2, 5, 1] },
{ id: "East", capacity: 2, queue: [3, 3, 4, 2] },
{ id: "South", capacity: 5, queue: [2, 1, 2, 3] },
{ id: "West", capacity: 3, queue: [5, 2, 1, 4] },
];
function initializeThroughput(gates) {
const summary = {};
for (const gate of gates) {
summary[gate.id] = 0;
};
return summary;
}
function processGateFlow(gate, tickIndex) {
let currentTickQueue = gate.queue[tickIndex];
let processed = 0;
while (currentTickQueue > 0 && processed < gate.capacity) {
currentTickQueue--;
processed++;
}
return {
processed: processed,
overflow: currentTickQueue
};
}
function rerouteOverflow(gates, currentGate, tickIndex, overflowAmount) {
const currentIndex = gates.indexOf(currentGate);
const nextGateIndex = (currentIndex + 1) % gates.length;
gates[nextGateIndex].queue[tickIndex] += overflowAmount;
console.log(
overflowAmount + " attendees rerouted to " +
gates[nextGateIndex].id
);
}
function handleGateAtTick(gates, gate, tickIndex, throughputSummary) {
console.log("\nProcessing " + gate.id + "...");
console.log(
gate.queue[tickIndex] + " attendees arriving."
);
const result = processGateFlow(gate, tickIndex);
throughputSummary[gate.id] += result.processed;
if (result.overflow > 0) {
console.log(
"Overflow of " + result.overflow +
" attendees. Rerouting..."
);
rerouteOverflow(gates, gate, tickIndex, result.overflow);
}
}
function printSummary(summary) {
console.log("\nThroughput Summary");
for (const gateId in summary) {
console.log(
gateId + ": " + summary[gateId] +
" attendees processed"
);
}
}
function simulateFestival(gates, timeBlock) {
console.log("\n" + timeBlock + " Simulation");
const throughputSummary = initializeThroughput(gates);
const maxTicks = gates[0].queue.length;
--fcc-editable-region--
--fcc-editable-region--
}
```

View File

@@ -0,0 +1,116 @@
---
id: 69bac1c29c13f446b39f524f
title: Step 29
challengeType: 1
dashedName: step-29
---
# --description--
You should now implement the main simulation loop. This loop will ensure that every gate is processed for each tick in the simulation until all ticks have been completed.
Create an empty `while` loop that continues as long as `tickIndex` is less than `maxTicks`.
# --hints--
You should create an empty `while` loop with the condition `(tickIndex < maxTicks)`.
```js
const cleaned = __helpers.removeWhiteSpace(__helpers.removeJSComments(code));
const viableSolutions = [
"while(tickIndex<maxTicks){}}",
"while(tickIndex<maxTicks){};}"
];
const endsCorrectly = viableSolutions.some(sol => cleaned.endsWith(sol));
assert(
endsCorrectly,
"In your `simulateFestival` function, you should create an empty `while` loop with the condition `(tickIndex < maxTicks)`."
);
```
# --seed--
## --seed-contents--
```js
const morningGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] },
];
const nightGates = [
{ id: "North", capacity: 4, queue: [6, 2, 5, 1] },
{ id: "East", capacity: 2, queue: [3, 3, 4, 2] },
{ id: "South", capacity: 5, queue: [2, 1, 2, 3] },
{ id: "West", capacity: 3, queue: [5, 2, 1, 4] },
];
function initializeThroughput(gates) {
const summary = {};
for (const gate of gates) {
summary[gate.id] = 0;
};
return summary;
}
function processGateFlow(gate, tickIndex) {
let currentTickQueue = gate.queue[tickIndex];
let processed = 0;
while (currentTickQueue > 0 && processed < gate.capacity) {
currentTickQueue--;
processed++;
}
return {
processed: processed,
overflow: currentTickQueue
};
}
function rerouteOverflow(gates, currentGate, tickIndex, overflowAmount) {
const currentIndex = gates.indexOf(currentGate);
const nextGateIndex = (currentIndex + 1) % gates.length;
gates[nextGateIndex].queue[tickIndex] += overflowAmount;
console.log(
overflowAmount + " attendees rerouted to " +
gates[nextGateIndex].id
);
}
function handleGateAtTick(gates, gate, tickIndex, throughputSummary) {
console.log("\nProcessing " + gate.id + "...");
console.log(
gate.queue[tickIndex] + " attendees arriving."
);
const result = processGateFlow(gate, tickIndex);
throughputSummary[gate.id] += result.processed;
if (result.overflow > 0) {
console.log(
"Overflow of " + result.overflow +
" attendees. Rerouting..."
);
rerouteOverflow(gates, gate, tickIndex, result.overflow);
}
}
function printSummary(summary) {
console.log("\nThroughput Summary");
for (const gateId in summary) {
console.log(
gateId + ": " + summary[gateId] +
" attendees processed"
);
}
}
function simulateFestival(gates, timeBlock) {
console.log("\n" + timeBlock + " Simulation");
const throughputSummary = initializeThroughput(gates);
const maxTicks = gates[0].queue.length;
let tickIndex = 0;
--fcc-editable-region--
--fcc-editable-region--
}
```

View File

@@ -0,0 +1,182 @@
---
id: 69bac1d7a104cfeccc356118
title: Step 31
challengeType: 1
dashedName: step-31
---
# --description--
To complete your `simulateFestival` function, display a summary of the simulation results. Call `printSummary()` with your local `throughputSummary` object.
# --hints--
You should call `printSummary()` with `throughputSummary`.
```js
const testGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] }
];
const originalPrintSummary = printSummary;
let printSummaryCallCount = 0;
let printSummaryArg = null;
try {
printSummary = function (arg) {
printSummaryCallCount++;
printSummaryArg = arg;
return originalPrintSummary(arg);
};
const consoleSpy = __helpers.spyOn(console, "log");
try {
simulateFestival(testGates, "Morning");
assert.strictEqual(
printSummaryCallCount,
1,
"printSummary should be called exactly once"
);
assert.isObject(
printSummaryArg,
"printSummary should be called with an object"
);
assert.strictEqual(
printSummaryArg.North,
14,
"After simulation, North should have processed 14 attendees total"
);
assert.strictEqual(
printSummaryArg.East,
11,
"After simulation, East should have processed 11 attendees total"
);
assert.strictEqual(
printSummaryArg.South,
11,
"After simulation, South should have processed 11 attendees total"
);
assert.strictEqual(
printSummaryArg.West,
7,
"After simulation, West should have processed 7 attendees total"
);
const allLogs = consoleSpy.calls.map(call => call[0]).join("");
assert.include(
allLogs,
"Throughput Summary",
"Summary should be printed with 'Throughput Summary' header"
);
} finally {
consoleSpy.restore();
}
} catch (err) {
assert.fail(err);
} finally {
printSummary = originalPrintSummary;
}
```
# --seed--
## --seed-contents--
```js
const morningGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] },
];
const nightGates = [
{ id: "North", capacity: 4, queue: [6, 2, 5, 1] },
{ id: "East", capacity: 2, queue: [3, 3, 4, 2] },
{ id: "South", capacity: 5, queue: [2, 1, 2, 3] },
{ id: "West", capacity: 3, queue: [5, 2, 1, 4] },
];
function initializeThroughput(gates) {
const summary = {};
for (const gate of gates) {
summary[gate.id] = 0;
};
return summary;
}
function processGateFlow(gate, tickIndex) {
let currentTickQueue = gate.queue[tickIndex];
let processed = 0;
while (currentTickQueue > 0 && processed < gate.capacity) {
currentTickQueue--;
processed++;
}
return {
processed: processed,
overflow: currentTickQueue
};
}
function rerouteOverflow(gates, currentGate, tickIndex, overflowAmount) {
const currentIndex = gates.indexOf(currentGate);
const nextGateIndex = (currentIndex + 1) % gates.length;
gates[nextGateIndex].queue[tickIndex] += overflowAmount;
console.log(
overflowAmount + " attendees rerouted to " +
gates[nextGateIndex].id
);
}
function handleGateAtTick(gates, gate, tickIndex, throughputSummary) {
console.log("\nProcessing " + gate.id + "...");
console.log(
gate.queue[tickIndex] + " attendees arriving."
);
const result = processGateFlow(gate, tickIndex);
throughputSummary[gate.id] += result.processed;
if (result.overflow > 0) {
console.log(
"Overflow of " + result.overflow +
" attendees. Rerouting..."
);
rerouteOverflow(gates, gate, tickIndex, result.overflow);
}
}
function printSummary(summary) {
console.log("\nThroughput Summary");
for (const gateId in summary) {
console.log(
gateId + ": " + summary[gateId] +
" attendees processed"
);
}
}
function simulateFestival(gates, timeBlock) {
console.log("\n" + timeBlock + " Simulation");
const throughputSummary = initializeThroughput(gates);
const maxTicks = gates[0].queue.length;
let tickIndex = 0;
while (tickIndex < maxTicks) {
console.log("\nTick " + (tickIndex + 1));
for (const gate of gates) {
handleGateAtTick(gates, gate, tickIndex, throughputSummary);
}
tickIndex++;
}
--fcc-editable-region--
--fcc-editable-region--
}
```

View File

@@ -0,0 +1,125 @@
---
id: 69bac1e1ae414b16a12e4041
title: Step 32
challengeType: 1
dashedName: step-32
---
# --description--
Finally, you can run your simulations.
Begin with the morning shift. Call `simulateFestival()` with `morningGates` and `"Morning"`.
# --hints--
You should call `simulateFestival()` with `morningGates` and `"Morning"`.
```js
const cleaned = __helpers.removeWhiteSpace(__helpers.removeJSComments(code));
const viableSolutions = [
`simulateFestival(morningGates,"Morning")`,
`simulateFestival(morningGates,"Morning");`
];
const endsCorrectly = viableSolutions.some(sol => cleaned.endsWith(sol));
assert(
endsCorrectly,
"You should call `simulateFestival()` with `morningGates` and Morning."
);
```
# --seed--
## --seed-contents--
```js
const morningGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] },
];
const nightGates = [
{ id: "North", capacity: 4, queue: [6, 2, 5, 1] },
{ id: "East", capacity: 2, queue: [3, 3, 4, 2] },
{ id: "South", capacity: 5, queue: [2, 1, 2, 3] },
{ id: "West", capacity: 3, queue: [5, 2, 1, 4] },
];
function initializeThroughput(gates) {
const summary = {};
for (const gate of gates) {
summary[gate.id] = 0;
};
return summary;
}
function processGateFlow(gate, tickIndex) {
let currentTickQueue = gate.queue[tickIndex];
let processed = 0;
while (currentTickQueue > 0 && processed < gate.capacity) {
currentTickQueue--;
processed++;
}
return {
processed: processed,
overflow: currentTickQueue
};
}
function rerouteOverflow(gates, currentGate, tickIndex, overflowAmount) {
const currentIndex = gates.indexOf(currentGate);
const nextGateIndex = (currentIndex + 1) % gates.length;
gates[nextGateIndex].queue[tickIndex] += overflowAmount;
console.log(
overflowAmount + " attendees rerouted to " +
gates[nextGateIndex].id
);
}
function handleGateAtTick(gates, gate, tickIndex, throughputSummary) {
console.log("\nProcessing " + gate.id + "...");
console.log(
gate.queue[tickIndex] + " attendees arriving."
);
const result = processGateFlow(gate, tickIndex);
throughputSummary[gate.id] += result.processed;
if (result.overflow > 0) {
console.log(
"Overflow of " + result.overflow +
" attendees. Rerouting..."
);
rerouteOverflow(gates, gate, tickIndex, result.overflow);
}
}
function printSummary(summary) {
console.log("\nThroughput Summary");
for (const gateId in summary) {
console.log(
gateId + ": " + summary[gateId] +
" attendees processed"
);
}
}
function simulateFestival(gates, timeBlock) {
console.log("\n" + timeBlock + " Simulation");
const throughputSummary = initializeThroughput(gates);
const maxTicks = gates[0].queue.length;
let tickIndex = 0;
while (tickIndex < maxTicks) {
console.log("\nTick " + (tickIndex + 1));
for (const gate of gates) {
handleGateAtTick(gates, gate, tickIndex, throughputSummary);
}
tickIndex++;
}
printSummary(throughputSummary);
}
--fcc-editable-region--
--fcc-editable-region--
```

View File

@@ -0,0 +1,152 @@
---
id: 69cfdc80443b715a8aa452a7
title: Step 3
challengeType: 1
dashedName: step-3
---
# --description--
To complete your `initializeThroughput` function:
- Loop through each gate in the input `gates` array. For each gate, add a property to `summary` where:
- The key is the gate's `id`.
- The value is `0`.
- After the loop, return the `summary` object.
Your `initializeThroughput` function should not mutate the source input array `gates`.
# --hints--
Calling `initializeThroughput()` with `[]` should return `{}` without mutating the source input.
```js
const input = [];
const original = JSON.parse(JSON.stringify(input));
const result = initializeThroughput(input);
assert.deepEqual(
result,
{},
"Calling `initializeThroughput([])` should return an empty object."
);
assert.deepEqual(
input,
original,
"`initializeThroughput` should not mutate the source array when given an empty array."
);
```
Calling `initializeThroughput()` with `[{ id: "North", capacity: 5, queue: [1, 2, 3] }]` should return `{ North: 0 }` without mutating the source input.
```js
const input = [{ id: "North", capacity: 5, queue: [1, 2, 3] }];
const original = JSON.parse(JSON.stringify(input));
const result = initializeThroughput(input);
assert.deepEqual(
result,
{ North: 0 },
"Calling `initializeThroughput([{ id: 'North', ... }])` should return `{ North: 0 }`."
);
assert.deepEqual(
input,
original,
"`initializeThroughput` should not mutate the source array when given one gate."
);
```
Calling `initializeThroughput()` with `[{ id: "North", capacity: 5, queue: [] }, { id: "East", capacity: 3, queue: [] }, { id: "South", capacity: 4, queue: [] }]` should return `{ North: 0, East: 0, South: 0}` without mutating the source input.
```js
const input = [
{ id: "North", capacity: 5, queue: [] },
{ id: "East", capacity: 3, queue: [] },
{ id: "South", capacity: 4, queue: [] }
];
const original = JSON.parse(JSON.stringify(input));
const result = initializeThroughput(input);
assert.deepEqual(
result,
{ North: 0, East: 0, South: 0 },
"Calling `initializeThroughput` with multiple gates should return an object with an entry for each gate id set to 0."
);
assert.deepEqual(
input,
original,
"`initializeThroughput` should not mutate the source array when given multiple gates."
);
```
You should use a `for` loop to iterate through each gate object inside of the input `gates` array.
```js
const cleaned = __helpers.removeWhiteSpace(__helpers.removeJSComments(initializeThroughput.toString()));
assert.match(cleaned, /for\s*\(/);
```
After the loop, you should return `summary`. This should be the final line in the function.
```js
const funcStr = __helpers.removeWhiteSpace(__helpers.removeJSComments(initializeThroughput.toString()));
assert.match(
funcStr,
/returnsummary;?}$/,
"Your `initializeThroughput` function should end with `return summary`."
);
```
Your `initializeThroughput` function should not mutate the source input array `gates`.
```js
const morningCopy = JSON.parse(JSON.stringify(morningGates));
const nightCopy = JSON.parse(JSON.stringify(nightGates));
initializeThroughput(morningGates);
initializeThroughput(nightGates);
assert.deepEqual(
morningGates,
morningCopy,
"`initializeThroughput` should not mutate the `morningGates` seed array."
);
assert.deepEqual(
nightGates,
nightCopy,
"`initializeThroughput` should not mutate the `nightGates` seed array."
);
```
# --seed--
## --seed-contents--
```js
const morningGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] },
];
const nightGates = [
{ id: "North", capacity: 4, queue: [6, 2, 5, 1] },
{ id: "East", capacity: 2, queue: [3, 3, 4, 2] },
{ id: "South", capacity: 5, queue: [2, 1, 2, 3] },
{ id: "West", capacity: 3, queue: [5, 2, 1, 4] },
];
function initializeThroughput(gates) {
const summary = {};
--fcc-editable-region--
--fcc-editable-region--
}
```

View File

@@ -0,0 +1,98 @@
---
id: 69d048937c7bb4b4c22ebb18
title: Step 8
challengeType: 1
dashedName: step-8
---
# --description--
Now it is time to process attendees through the gate. Inside the `while` loop:
- Decrement `currentTickQueue` by 1 to show one attendee has passed. Use the decrement operator (`--`).
- Increment `processed` by 1 to track how many attendees were processed. Use the increment operator (`++`).
# --hints--
Inside your `while` loop, you should decrement `currentTickQueue` using the decrement operator `--` and increment `processed` using the increment operator `++`.
```js
const rawFuncStr = __helpers.removeJSComments(processGateFlow.toString());
const opsRegex = /\s*processed\+\+\s*;?\s*currentTickQueue--\s*|\s*currentTickQueue--\s*;?\s*processed\+\+/;
assert(
opsRegex.test(rawFuncStr),
"Inside your while loop, `processed++` and `currentTickQueue--` must appear next to each other, separated by a semicolon or newline."
);
const cleaned1 = __helpers.removeWhiteSpace(rawFuncStr);
const viableSolutions1 = [
"processed++;currentTickQueue--;}}",
"processed++currentTickQueue--;}}",
"processed++;currentTickQueue--}}",
"processed++currentTickQueue--}}",
"currentTickQueue--;processed++;}}",
"currentTickQueue--processed++;}}",
"currentTickQueue--;processed++}}",
"currentTickQueue--processed++}}"
];
const endsCorrectly1 = viableSolutions1.some(sol1 => cleaned1.endsWith(sol1));
assert(
endsCorrectly1,
"Your function must end with the while loop and both increment and decrement operations inside of it."
);
const cleaned2 = __helpers.removeWhiteSpace(__helpers.removeJSComments(code));
const viableSolutions2 = [
"while(currentTickQueue>0&&processed<gate.capacity){processed++;currentTickQueue--;}}",
"while(currentTickQueue>0&&processed<gate.capacity){processed++currentTickQueue--;}}",
"while(currentTickQueue>0&&processed<gate.capacity){processed++;currentTickQueue--}}",
"while(currentTickQueue>0&&processed<gate.capacity){processed++currentTickQueue--}}",
"while(currentTickQueue>0&&processed<gate.capacity){currentTickQueue--;processed++;}}",
"while(currentTickQueue>0&&processed<gate.capacity){currentTickQueue--processed++;}}",
"while(currentTickQueue>0&&processed<gate.capacity){currentTickQueue--;processed++}}",
"while(currentTickQueue>0&&processed<gate.capacity){currentTickQueue--processed++}}"
];
const endsCorrectly2 = viableSolutions2.some(sol2 => cleaned2.endsWith(sol2));
assert(
endsCorrectly2,
"Your while loop must have both, and only both, of the increment and decrement operations inside it."
);
```
# --seed--
## --seed-contents--
```js
const morningGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] },
];
const nightGates = [
{ id: "North", capacity: 4, queue: [6, 2, 5, 1] },
{ id: "East", capacity: 2, queue: [3, 3, 4, 2] },
{ id: "South", capacity: 5, queue: [2, 1, 2, 3] },
{ id: "West", capacity: 3, queue: [5, 2, 1, 4] },
];
function initializeThroughput(gates) {
const summary = {};
for (const gate of gates) {
summary[gate.id] = 0;
};
return summary;
}
function processGateFlow(gate, tickIndex) {
let currentTickQueue = gate.queue[tickIndex];
let processed = 0;
while (currentTickQueue > 0 && processed < gate.capacity) {
--fcc-editable-region--
--fcc-editable-region--
}
}
```

View File

@@ -0,0 +1,236 @@
---
id: 69d08c139139f65a17cc615c
title: Step 30
challengeType: 1
dashedName: step-30
---
# --description--
Inside your `while` loop:
- Log the message, `"\nTick " + (tickIndex + 1)`.
- Loop through each gate in the `gates` array and call `handleGateAtTick()` with these arguments:
- `gates`: the full gates input array.
- `gate`: the current gate object.
- `tickIndex`: the current tick.
- `throughputSummary`: the local object tracking total attendees processed per gate.
- Increment `tickIndex` by 1 to move to the next tick.
# --hints--
You should log the following message to the console, `"\nTick " + (tickIndex + 1)`.
```js
const testGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] }
];
const spy = __helpers.spyOn(console, "log");
try {
simulateFestival(testGates, "Morning");
const tickMessages = spy.calls.filter(call => call[0].includes("Tick"));
assert.lengthOf(
tickMessages,
4,
"Should log a tick message for each tick (4 ticks total)"
);
assert.match(
tickMessages[0][0],
/\nTick 1/,
"First tick should log '\\nTick 1'"
);
assert.match(
tickMessages[1][0],
/\nTick 2/,
"Second tick should log '\\nTick 2'"
);
assert.match(
tickMessages[2][0],
/\nTick 3/,
"Third tick should log '\\nTick 3'"
);
assert.match(
tickMessages[3][0],
/\nTick 4/,
"Fourth tick should log '\\nTick 4'"
);
} catch (err) {
assert.fail(err);
} finally {
spy.restore();
}
```
After logging to the console, you should loop through each gate in the `gates` array and call `handleGateAtTick()` with `gates`, `gate`, `tickIndex`, and `throughputSummary`.
```js
const testGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] }
];
const originalHandleGateAtTick = handleGateAtTick;
let handleGateCallCount = 0;
try {
handleGateAtTick = function (...args) {
handleGateCallCount++;
return originalHandleGateAtTick(...args);
};
const consoleSpy = __helpers.spyOn(console, "log");
try {
simulateFestival(testGates, "Morning");
const expectedCallCount = testGates.length * testGates[0].queue.length;
assert.strictEqual(
handleGateCallCount,
expectedCallCount,
`handleGateAtTick should be called ${expectedCallCount} times (4 gates × 4 ticks)`
);
} finally {
consoleSpy.restore();
}
} catch (err) {
assert.fail(err);
} finally {
handleGateAtTick = originalHandleGateAtTick;
}
```
After your loop through the `gates` array, you should increment `tickIndex` by 1.
```js
const testGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] }
];
const consoleSpy = __helpers.spyOn(console, "log");
try {
simulateFestival(testGates, "Morning");
const allLogs = consoleSpy.calls.length;
assert.isTrue(
allLogs > 0,
"Function should complete and log messages (without infinite loop)"
);
const tickMessages = consoleSpy.calls.filter(call => call[0].includes("Tick"));
assert.lengthOf(
tickMessages,
4,
"tickIndex should be incremented properly to complete all 4 ticks without infinite loop"
);
} catch (err) {
assert.fail(err);
} finally {
consoleSpy.restore();
}
```
# --seed--
## --seed-contents--
```js
const morningGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] },
];
const nightGates = [
{ id: "North", capacity: 4, queue: [6, 2, 5, 1] },
{ id: "East", capacity: 2, queue: [3, 3, 4, 2] },
{ id: "South", capacity: 5, queue: [2, 1, 2, 3] },
{ id: "West", capacity: 3, queue: [5, 2, 1, 4] },
];
function initializeThroughput(gates) {
const summary = {};
for (const gate of gates) {
summary[gate.id] = 0;
};
return summary;
}
function processGateFlow(gate, tickIndex) {
let currentTickQueue = gate.queue[tickIndex];
let processed = 0;
while (currentTickQueue > 0 && processed < gate.capacity) {
currentTickQueue--;
processed++;
}
return {
processed: processed,
overflow: currentTickQueue
};
}
function rerouteOverflow(gates, currentGate, tickIndex, overflowAmount) {
const currentIndex = gates.indexOf(currentGate);
const nextGateIndex = (currentIndex + 1) % gates.length;
gates[nextGateIndex].queue[tickIndex] += overflowAmount;
console.log(
overflowAmount + " attendees rerouted to " +
gates[nextGateIndex].id
);
}
function handleGateAtTick(gates, gate, tickIndex, throughputSummary) {
console.log("\nProcessing " + gate.id + "...");
console.log(
gate.queue[tickIndex] + " attendees arriving."
);
const result = processGateFlow(gate, tickIndex);
throughputSummary[gate.id] += result.processed;
if (result.overflow > 0) {
console.log(
"Overflow of " + result.overflow +
" attendees. Rerouting..."
);
rerouteOverflow(gates, gate, tickIndex, result.overflow);
}
}
function printSummary(summary) {
console.log("\nThroughput Summary");
for (const gateId in summary) {
console.log(
gateId + ": " + summary[gateId] +
" attendees processed"
);
}
}
function simulateFestival(gates, timeBlock) {
console.log("\n" + timeBlock + " Simulation");
const throughputSummary = initializeThroughput(gates);
const maxTicks = gates[0].queue.length;
let tickIndex = 0;
while (tickIndex < maxTicks) {
--fcc-editable-region--
--fcc-editable-region--
}
}
```

View File

@@ -0,0 +1,219 @@
---
id: 69d1b6d762a5a7edeb997258
title: Step 33
challengeType: 1
dashedName: step-33
---
# --description--
Simulate the night shift by calling `simulateFestival()` with `nightGates` and `"Night"`.
With that, your simulations are complete!
# --hints--
You should call `simulateFestival()` with `nightGates` and `"Night"`.
```js
const cleaned = __helpers.removeWhiteSpace(__helpers.removeJSComments(code));
const viableSolutions = [
`simulateFestival(nightGates,"Night")`,
`simulateFestival(nightGates,"Night");`
];
const endsCorrectly = viableSolutions.some(sol => cleaned.endsWith(sol));
assert(
endsCorrectly,
"You should call `simulateFestival()` with `nightGates` and Night."
);
```
# --seed--
## --seed-contents--
```js
const morningGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] },
];
const nightGates = [
{ id: "North", capacity: 4, queue: [6, 2, 5, 1] },
{ id: "East", capacity: 2, queue: [3, 3, 4, 2] },
{ id: "South", capacity: 5, queue: [2, 1, 2, 3] },
{ id: "West", capacity: 3, queue: [5, 2, 1, 4] },
];
function initializeThroughput(gates) {
const summary = {};
for (const gate of gates) {
summary[gate.id] = 0;
};
return summary;
}
function processGateFlow(gate, tickIndex) {
let currentTickQueue = gate.queue[tickIndex];
let processed = 0;
while (currentTickQueue > 0 && processed < gate.capacity) {
currentTickQueue--;
processed++;
}
return {
processed: processed,
overflow: currentTickQueue
};
}
function rerouteOverflow(gates, currentGate, tickIndex, overflowAmount) {
const currentIndex = gates.indexOf(currentGate);
const nextGateIndex = (currentIndex + 1) % gates.length;
gates[nextGateIndex].queue[tickIndex] += overflowAmount;
console.log(
overflowAmount + " attendees rerouted to " +
gates[nextGateIndex].id
);
}
function handleGateAtTick(gates, gate, tickIndex, throughputSummary) {
console.log("\nProcessing " + gate.id + "...");
console.log(
gate.queue[tickIndex] + " attendees arriving."
);
const result = processGateFlow(gate, tickIndex);
throughputSummary[gate.id] += result.processed;
if (result.overflow > 0) {
console.log(
"Overflow of " + result.overflow +
" attendees. Rerouting..."
);
rerouteOverflow(gates, gate, tickIndex, result.overflow);
}
}
function printSummary(summary) {
console.log("\nThroughput Summary");
for (const gateId in summary) {
console.log(
gateId + ": " + summary[gateId] +
" attendees processed"
);
}
}
function simulateFestival(gates, timeBlock) {
console.log("\n" + timeBlock + " Simulation");
const throughputSummary = initializeThroughput(gates);
const maxTicks = gates[0].queue.length;
let tickIndex = 0;
while (tickIndex < maxTicks) {
console.log("\nTick " + (tickIndex + 1));
for (const gate of gates) {
handleGateAtTick(gates, gate, tickIndex, throughputSummary);
}
tickIndex++;
}
printSummary(throughputSummary);
}
simulateFestival(morningGates, "Morning");
--fcc-editable-region--
--fcc-editable-region--
```
# --solutions--
```js
const morningGates = [
{ id: "North", capacity: 5, queue: [3, 6, 2, 4] },
{ id: "East", capacity: 3, queue: [2, 4, 3, 5] },
{ id: "South", capacity: 4, queue: [1, 2, 3, 1] },
{ id: "West", capacity: 2, queue: [4, 1, 2, 3] },
];
const nightGates = [
{ id: "North", capacity: 4, queue: [6, 2, 5, 1] },
{ id: "East", capacity: 2, queue: [3, 3, 4, 2] },
{ id: "South", capacity: 5, queue: [2, 1, 2, 3] },
{ id: "West", capacity: 3, queue: [5, 2, 1, 4] },
];
function initializeThroughput(gates) {
const summary = {};
for (const gate of gates) {
summary[gate.id] = 0;
};
return summary;
}
function processGateFlow(gate, tickIndex) {
let currentTickQueue = gate.queue[tickIndex];
let processed = 0;
while (currentTickQueue > 0 && processed < gate.capacity) {
currentTickQueue--;
processed++;
}
return {
processed: processed,
overflow: currentTickQueue
};
}
function rerouteOverflow(gates, currentGate, tickIndex, overflowAmount) {
const currentIndex = gates.indexOf(currentGate);
const nextGateIndex = (currentIndex + 1) % gates.length;
gates[nextGateIndex].queue[tickIndex] += overflowAmount;
console.log(
overflowAmount + " attendees rerouted to " +
gates[nextGateIndex].id
);
}
function handleGateAtTick(gates, gate, tickIndex, throughputSummary) {
console.log("\nProcessing " + gate.id + "...");
console.log(
gate.queue[tickIndex] + " attendees arriving."
);
const result = processGateFlow(gate, tickIndex);
throughputSummary[gate.id] += result.processed;
if (result.overflow > 0) {
console.log(
"Overflow of " + result.overflow +
" attendees. Rerouting..."
);
rerouteOverflow(gates, gate, tickIndex, result.overflow);
}
}
function printSummary(summary) {
console.log("\nThroughput Summary");
for (const gateId in summary) {
console.log(
gateId + ": " + summary[gateId] +
" attendees processed"
);
}
}
function simulateFestival(gates, timeBlock) {
console.log("\n" + timeBlock + " Simulation");
const throughputSummary = initializeThroughput(gates);
const maxTicks = gates[0].queue.length;
let tickIndex = 0;
while (tickIndex < maxTicks) {
console.log("\nTick " + (tickIndex + 1));
for (const gate of gates) {
handleGateAtTick(gates, gate, tickIndex, throughputSummary);
}
tickIndex++;
}
printSummary(throughputSummary);
}
simulateFestival(morningGates, "Morning");
simulateFestival(nightGates, "Night");
```

View File

@@ -0,0 +1,44 @@
{
"isUpcomingChange": false,
"dashedName": "workshop-festival-crowd-flow-simulator",
"helpCategory": "JavaScript",
"blockLayout": "challenge-grid",
"challengeOrder": [
{ "id": "69baafd6d683dd9921b75db3", "title": "Step 1" },
{ "id": "69bab8292750d84cac5b52a0", "title": "Step 2" },
{ "id": "69cfdc80443b715a8aa452a7", "title": "Step 3" },
{ "id": "69babdf3f896711c11516373", "title": "Step 4" },
{ "id": "69babea99725b43a01adb6d1", "title": "Step 5" },
{ "id": "69babf2bf78bade75fda0326", "title": "Step 6" },
{ "id": "69babf3f446433af8d065bb5", "title": "Step 7" },
{ "id": "69d048937c7bb4b4c22ebb18", "title": "Step 8" },
{ "id": "69babfc35c3c58d0993d404d", "title": "Step 9" },
{ "id": "69babfd65c4c4632a0c76f63", "title": "Step 10" },
{ "id": "69bac013466bd9bad0b809b1", "title": "Step 11" },
{ "id": "69bac027df64d4433c708d44", "title": "Step 12" },
{ "id": "69bac03ae5faf2979a3339ff", "title": "Step 13" },
{ "id": "69bac047282614c7ef87d370", "title": "Step 14" },
{ "id": "69bac067cd15c4685d07906d", "title": "Step 15" },
{ "id": "69bac073b1de8b484bbccc94", "title": "Step 16" },
{ "id": "69bac08105bec16db267dcbf", "title": "Step 17" },
{ "id": "69bac0a011a9c1f735d306c2", "title": "Step 18" },
{ "id": "69bac0d5a0b16122a2a938a4", "title": "Step 19" },
{ "id": "69bac0e7112d02531998dbf0", "title": "Step 20" },
{ "id": "69bac0f9659af01091c5967d", "title": "Step 21" },
{ "id": "69bac11611f4c349e8e666ec", "title": "Step 22" },
{ "id": "69bac12483f656898154f969", "title": "Step 23" },
{ "id": "69bac146b5f30209b4179af1", "title": "Step 24" },
{ "id": "69bac15062ac8a348b84fe46", "title": "Step 25" },
{ "id": "69bac17a4c53a3812b595eb9", "title": "Step 26" },
{ "id": "69bac18fe3729f6761344365", "title": "Step 27" },
{ "id": "69bac1a094d01d84ae4c9e75", "title": "Step 28" },
{ "id": "69bac1c29c13f446b39f524f", "title": "Step 29" },
{ "id": "69d08c139139f65a17cc615c", "title": "Step 30" },
{ "id": "69bac1d7a104cfeccc356118", "title": "Step 31" },
{ "id": "69bac1e1ae414b16a12e4041", "title": "Step 32" },
{ "id": "69d1b6d762a5a7edeb997258", "title": "Step 33" }
],
"blockLabel": "workshop",
"usesMultifileEditor": true,
"hasEditableBoundaries": true
}

View File

@@ -107,6 +107,7 @@
"lab-chunky-monkey",
"lab-profile-lookup",
"lab-repeat-a-string",
"workshop-festival-crowd-flow-simulator",
"lab-missing-letter-detector",
"review-javascript-loops",
"quiz-javascript-loops"