mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-05-05 18:01:45 -04:00
feat(curriculum): add Festival Crowd Flow Simulator Workshop - JavaScript v9 (#66551)
This commit is contained in:
@@ -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": [
|
||||
|
||||
@@ -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--
|
||||
```
|
||||
@@ -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--
|
||||
}
|
||||
```
|
||||
@@ -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--
|
||||
```
|
||||
@@ -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--
|
||||
}
|
||||
```
|
||||
@@ -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--
|
||||
}
|
||||
```
|
||||
@@ -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&¤tTickQueue>0){}}",
|
||||
"while((processed<gate.capacity)&&(currentTickQueue>0)){}}",
|
||||
"while(currentTickQueue>0&&processed<gate.capacity){};}",
|
||||
"while((currentTickQueue>0)&&(processed<gate.capacity)){};}",
|
||||
"while(processed<gate.capacity&¤tTickQueue>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--
|
||||
}
|
||||
```
|
||||
@@ -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--
|
||||
}
|
||||
```
|
||||
@@ -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--
|
||||
```
|
||||
@@ -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--
|
||||
}
|
||||
```
|
||||
@@ -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--
|
||||
}
|
||||
```
|
||||
@@ -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 gate’s 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--
|
||||
}
|
||||
```
|
||||
@@ -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--
|
||||
}
|
||||
```
|
||||
@@ -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, it’s 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--
|
||||
```
|
||||
@@ -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--
|
||||
}
|
||||
```
|
||||
@@ -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--
|
||||
}
|
||||
```
|
||||
@@ -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--
|
||||
}
|
||||
```
|
||||
@@ -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--
|
||||
}
|
||||
```
|
||||
@@ -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--
|
||||
}
|
||||
```
|
||||
@@ -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--
|
||||
```
|
||||
@@ -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--
|
||||
}
|
||||
```
|
||||
@@ -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--
|
||||
}
|
||||
```
|
||||
@@ -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--
|
||||
```
|
||||
@@ -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--
|
||||
}
|
||||
```
|
||||
@@ -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--
|
||||
}
|
||||
```
|
||||
@@ -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 gate’s 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--
|
||||
}
|
||||
```
|
||||
@@ -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--
|
||||
}
|
||||
```
|
||||
@@ -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--
|
||||
}
|
||||
```
|
||||
@@ -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--
|
||||
}
|
||||
```
|
||||
@@ -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--
|
||||
```
|
||||
@@ -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--
|
||||
}
|
||||
```
|
||||
@@ -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--
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -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--
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -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");
|
||||
```
|
||||
@@ -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
|
||||
}
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user