mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-06-19 21:09:51 +08:00
feat(curriculum): add voting system lab (#57208)
Co-authored-by: Dario-DC <105294544+Dario-DC@users.noreply.github.com> Co-authored-by: Tom <20648924+moT01@users.noreply.github.com>
This commit is contained in:
parent
75f480c948
commit
7260918523
@ -3101,7 +3101,12 @@
|
||||
]
|
||||
},
|
||||
"cvsw": { "title": "226", "intro": [] },
|
||||
"cvs1": { "title": "227", "intro": [] },
|
||||
"lab-voting-system": {
|
||||
"title": "Build a Voting System",
|
||||
"intro": [
|
||||
"In this lab, you will build a voting system using Maps and Sets."
|
||||
]
|
||||
},
|
||||
"review-javascript-maps-and-sets": {
|
||||
"title": "JavaScript Maps and Sets Review",
|
||||
"intro": [
|
||||
|
||||
@ -0,0 +1,9 @@
|
||||
---
|
||||
title: Introduction to the Build a Voting System
|
||||
block: lab-voting-system
|
||||
superBlock: full-stack-developer
|
||||
---
|
||||
|
||||
## Introduction to the Build a Voting System
|
||||
|
||||
In this lab, you will build a voting system using Maps and Sets.
|
||||
11
curriculum/challenges/_meta/lab-voting-system/meta.json
Normal file
11
curriculum/challenges/_meta/lab-voting-system/meta.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "Build a Voting System",
|
||||
"isUpcomingChange": true,
|
||||
"usesMultifileEditor": true,
|
||||
"dashedName": "lab-voting-system",
|
||||
"superBlock": "full-stack-developer",
|
||||
"challengeOrder": [{ "id": "673b567e3ba535dda140d278", "title": "Build a Voting System" }],
|
||||
"helpCategory": "JavaScript",
|
||||
"blockType": "lab",
|
||||
"blockLayout": "link"
|
||||
}
|
||||
@ -0,0 +1,352 @@
|
||||
---
|
||||
id: 673b567e3ba535dda140d278
|
||||
title: Build a Voting System
|
||||
challengeType: 14
|
||||
dashedName: build-a-voting-system
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
In this lab, you will build a voting system that uses `Map` to create a poll and `Set` to prevent duplicate voting.
|
||||
|
||||
**Objective:** Fulfill the user stories below and get all the tests to pass to complete the lab.
|
||||
|
||||
**User Stories:**
|
||||
|
||||
1. You should initialize a `poll` variable to a new `Map` object.
|
||||
|
||||
2. You should have a function `addOption` that accepts a parameter `option`.
|
||||
|
||||
3. In the `addOption` function:
|
||||
|
||||
- If the `option` does not already exist in the poll, it should be added to the poll with an empty `Set` as its value to track voters. You should also return the message `Option "<option>" added to the poll.`
|
||||
|
||||
- If the `option` already exists, it should return the message `Option "<option>" already exists.`.
|
||||
|
||||
- If you try to add an empty option, the function should return the message `Option cannot be empty.`.
|
||||
|
||||
4. You should have a function `vote` that accepts two parameters, `option` (the option to vote for) and `voterId` (a unique ID for the voter).
|
||||
|
||||
5. In the `vote` function:
|
||||
|
||||
- If the `option` does not exist in the poll, the function should return the message `Option "<option>" does not exist.`.
|
||||
|
||||
- If the `option` exists, the function should check if the `voterId` has already voted for this `option`.
|
||||
|
||||
- If the voter has already voted, the function should display the message `Voter <voterId> has already voted for "<option>".`
|
||||
|
||||
- If the voter has not voted, `voterId` should be added to the `Set` of `voters` for this option. The function should return the message `Voter <voterId> voted for "<option>".`
|
||||
|
||||
|
||||
6. You should have at least three options in your `poll`.
|
||||
|
||||
7. Your `poll` should have at least three votes.
|
||||
|
||||
8. You should have a function `displayResults` that returns the poll results in the following format:
|
||||
|
||||
```js
|
||||
Poll Results:
|
||||
OptionA: N votes
|
||||
OptionB: N votes
|
||||
.
|
||||
.
|
||||
|
||||
/*
|
||||
sample output
|
||||
|
||||
Poll Results:
|
||||
Turkey: 2 votes
|
||||
Morocco: 1 votes
|
||||
*/
|
||||
```
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have a `poll` variable initialized to a new `Map` object.
|
||||
|
||||
```js
|
||||
assert.exists(poll);
|
||||
assert.instanceOf(poll, Map);
|
||||
```
|
||||
|
||||
You should define a function `addOption` that accepts a parameter `option`.
|
||||
|
||||
```js
|
||||
assert.isFunction(addOption);
|
||||
assert.match(
|
||||
addOption.toString(),
|
||||
/^function\s+addOption\s*\(\s*option\s*\)\s*\{|\(?\s*option\s*\)?\s*=>/
|
||||
);
|
||||
```
|
||||
|
||||
You should define a function `vote` that accepts two parameters, `option` and `voterId`.
|
||||
|
||||
```js
|
||||
assert.isFunction(vote);
|
||||
assert.match(vote.toString(), /\(\s*option\s*,\s*voterId\s*\)/);
|
||||
```
|
||||
|
||||
You should define a function `displayResults` to display the poll results.
|
||||
|
||||
```js
|
||||
assert.isFunction(displayResults);
|
||||
```
|
||||
|
||||
You should have at least three options in your `poll`.
|
||||
|
||||
```js
|
||||
assert.lengthOf(poll, 3);
|
||||
```
|
||||
|
||||
Your `poll` should have at least three votes.
|
||||
|
||||
```js
|
||||
let totalVotes = 0;
|
||||
for (let voters of poll.values()) {
|
||||
totalVotes += voters.size;
|
||||
}
|
||||
assert.isAtLeast(totalVotes, 3);
|
||||
```
|
||||
|
||||
You should ensure each voting option maps to a `Set` object.
|
||||
|
||||
```js
|
||||
const pollCopy = new Map(poll);
|
||||
try {
|
||||
poll.clear();
|
||||
|
||||
addOption("Turkey");
|
||||
assert.instanceOf(poll.get("Turkey"), Set);
|
||||
|
||||
} finally {
|
||||
poll.clear();
|
||||
pollCopy.forEach((val, key) => {
|
||||
poll.set(key, val);
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
`addOption("Egypt")` should return `Option "Egypt" added to the poll.`
|
||||
|
||||
```js
|
||||
const pollCopy = new Map(poll);
|
||||
try {
|
||||
poll.clear();
|
||||
assert.equal(addOption("Egypt"), 'Option "Egypt" added to the poll.');
|
||||
} finally {
|
||||
poll.clear();
|
||||
pollCopy.forEach((val, key) => {
|
||||
poll.set(key, val);
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
Adding an empty option should return `"Option cannot be empty."`
|
||||
|
||||
```js
|
||||
assert.equal(addOption(""), 'Option cannot be empty.');
|
||||
```
|
||||
|
||||
When `Turkey` is already added, `addOption("Turkey")` should return `Option "Turkey" already exists.`
|
||||
|
||||
```js
|
||||
const pollCopy = new Map(poll);
|
||||
try {
|
||||
poll.clear();
|
||||
addOption("Turkey");
|
||||
addOption("Turkey");
|
||||
assert.equal(addOption("Turkey"), 'Option "Turkey" already exists.');
|
||||
|
||||
} finally {
|
||||
poll.clear();
|
||||
pollCopy.forEach((val, key) => {
|
||||
poll.set(key, val);
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
When `Malysia` exists in the voting options, `vote("Malysia", "traveler1")` should return `Voter traveler1 voted for "Malysia".`
|
||||
|
||||
```js
|
||||
const pollCopy = new Map(poll);
|
||||
try {
|
||||
poll.clear();
|
||||
addOption("Malysia");
|
||||
assert.equal(vote("Malysia", "traveler1"), 'Voter traveler1 voted for "Malysia".');
|
||||
} finally {
|
||||
poll.clear();
|
||||
pollCopy.forEach((val, key) => {
|
||||
poll.set(key, val);
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
`vote` should update the `Set` of voters for an option.
|
||||
|
||||
```js
|
||||
const pollCopy = new Map(poll);
|
||||
try {
|
||||
poll.clear();
|
||||
addOption("Alaska");
|
||||
vote("Alaska", "seal");
|
||||
assert.isTrue(poll.get("Alaska").has("seal"));
|
||||
|
||||
} finally {
|
||||
poll.clear();
|
||||
pollCopy.forEach((val, key) => {
|
||||
poll.set(key, val);
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
When `traveler1` tries to vote for `Algeria` again, `vote("Algeria", "traveler1")` should return `Voter traveler1 has already voted for "Algeria".`
|
||||
|
||||
```js
|
||||
const pollCopy = new Map(poll);
|
||||
try {
|
||||
poll.clear();
|
||||
addOption("Algeria");
|
||||
vote("Algeria", "traveler1");
|
||||
assert.equal(vote("Algeria", "traveler1"), 'Voter traveler1 has already voted for "Algeria".');
|
||||
} finally {
|
||||
poll.clear();
|
||||
pollCopy.forEach((val, key) => {
|
||||
poll.set(key, val);
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
Duplicate votes should not increase the size of the `Set`.
|
||||
|
||||
```js
|
||||
const pollCopy = new Map(poll);
|
||||
try {
|
||||
poll.clear();
|
||||
addOption("Turkey");
|
||||
vote("Turkey", "traveler1");
|
||||
const voterSet = poll.get("Turkey");
|
||||
const initialSize = voterSet.size;
|
||||
|
||||
vote("Turkey", "traveler1");
|
||||
assert.equal(voterSet.size, initialSize);
|
||||
} finally {
|
||||
poll.clear();
|
||||
pollCopy.forEach((val, key) => {
|
||||
poll.set(key, val);
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
When `Nigeria` is not in the voting options, `vote("Nigeria", "traveler2")` should return `Option "Nigeria" does not exist.`
|
||||
|
||||
```js
|
||||
const pollCopy = new Map(poll);
|
||||
try {
|
||||
poll.clear();
|
||||
assert.equal(vote("Nigeria", "traveler2"), 'Option "Nigeria" does not exist.');
|
||||
} finally {
|
||||
poll.clear();
|
||||
pollCopy.forEach((val, key) => {
|
||||
poll.set(key, val);
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
A unique option should be able to receive multiple votes.
|
||||
|
||||
```js
|
||||
const pollCopy = new Map(poll);
|
||||
try {
|
||||
poll.clear();
|
||||
addOption("Bali");
|
||||
assert.equal(vote("Bali", "traveler1"), 'Voter traveler1 voted for "Bali".');
|
||||
assert.equal(vote("Bali", "traveler2"), 'Voter traveler2 voted for "Bali".');
|
||||
assert.equal(poll.get("Bali").size, 2);
|
||||
} finally {
|
||||
poll.clear();
|
||||
pollCopy.forEach((val, key) => {
|
||||
poll.set(key, val);
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
`displayResults()` should return the results in the correct format.
|
||||
|
||||
```js
|
||||
|
||||
const pollCopy = new Map(poll);
|
||||
try {
|
||||
poll.clear();
|
||||
addOption("Turkey");
|
||||
addOption("Morocco");
|
||||
|
||||
vote("Turkey", "traveler1");
|
||||
vote("Turkey", "traveler2");
|
||||
vote("Morocco", "traveler3");
|
||||
|
||||
assert.equal(displayResults(), "Poll Results:\nTurkey: 2 votes\nMorocco: 1 votes");
|
||||
} finally {
|
||||
poll.clear();
|
||||
pollCopy.forEach((val, key) => {
|
||||
poll.set(key, val);
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
const poll = new Map();
|
||||
|
||||
function addOption(option) {
|
||||
if (!option || option.trim() === "") {
|
||||
return "Option cannot be empty.";
|
||||
}
|
||||
if (!poll.has(option)) {
|
||||
poll.set(option, new Set());
|
||||
return `Option "${option}" added to the poll.`;
|
||||
} else {
|
||||
return `Option "${option}" already exists.`;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function vote(option, voterId) {
|
||||
if (!poll.has(option)) {
|
||||
return `Option "${option}" does not exist.`;
|
||||
}
|
||||
const voters = poll.get(option);
|
||||
if (voters.has(voterId)) {
|
||||
return `Voter ${voterId} has already voted for "${option}".`;
|
||||
} else {
|
||||
voters.add(voterId);
|
||||
return `Voter ${voterId} voted for "${option}".`;
|
||||
}
|
||||
}
|
||||
|
||||
function displayResults() {
|
||||
let results = "Poll Results:\n";
|
||||
for (let [option, voters] of poll.entries()) {
|
||||
results += `${option}: ${voters.size} votes\n`;
|
||||
}
|
||||
return results.trim();
|
||||
}
|
||||
|
||||
|
||||
addOption("Turkey");
|
||||
addOption("Morocco");
|
||||
addOption("Spain");
|
||||
|
||||
vote("Turkey", "traveler1");
|
||||
vote("Turkey", "traveler2");
|
||||
vote("Morocco", "traveler3");
|
||||
|
||||
```
|
||||
@ -468,6 +468,7 @@
|
||||
"dashedName": "maps-and-sets",
|
||||
"blocks": [
|
||||
{ "dashedName": "lecture-working-with-maps-and-sets" },
|
||||
{ "dashedName": "lab-voting-system" },
|
||||
{ "dashedName": "review-javascript-maps-and-sets" },
|
||||
{ "dashedName": "quiz-javascript-maps-and-sets" }
|
||||
]
|
||||
|
||||
Loading…
Reference in New Issue
Block a user