Skip to content

Bird Watcher: Prevent not following the instructions #2667

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 11, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions exercises/concept/bird-watcher/.docs/instructions.md
Original file line number Diff line number Diff line change
@@ -6,11 +6,10 @@ You already digitalized the bird counts per day for the past weeks that you kept

Now you want to determine the total number of birds that you counted, calculate the bird count for a specific week and correct a counting mistake.

<!-- prettier-ignore-start -->
<!-- prettier-ignore -->
~~~~exercism/note
To practice, use a for loop to solve each of the tasks below.
To practice, use a `for` loop to solve each of the tasks below.
~~~~
<!-- prettier-ignore-end -->

## 1. Determine the total number of birds that you counted so far

7 changes: 5 additions & 2 deletions exercises/concept/bird-watcher/.meta/exemplar.js
Original file line number Diff line number Diff line change
@@ -12,9 +12,11 @@
*/
export function totalBirdCount(birdsPerDay) {
let total = 0;

for (let i = 0; i < birdsPerDay.length; i++) {
total += birdsPerDay[i];
}

return total;
}

@@ -27,10 +29,12 @@ export function totalBirdCount(birdsPerDay) {
*/
export function birdsInWeek(birdsPerDay, week) {
let total = 0;

const start = 7 * (week - 1);
for (let i = start; i < start + 7; i++) {
total += birdsPerDay[i];
}

return total;
}

@@ -39,11 +43,10 @@ export function birdsInWeek(birdsPerDay, week) {
* by one for every second day.
*
* @param {number[]} birdsPerDay
* @returns {number[]} corrected bird count data
* @returns {void} should not return anything
*/
export function fixBirdCountLog(birdsPerDay) {
for (let i = 0; i < birdsPerDay.length; i += 2) {
birdsPerDay[i]++;
}
return birdsPerDay;
}
2 changes: 1 addition & 1 deletion exercises/concept/bird-watcher/bird-watcher.js
Original file line number Diff line number Diff line change
@@ -30,7 +30,7 @@ export function birdsInWeek(birdsPerDay, week) {
* by one for every second day.
*
* @param {number[]} birdsPerDay
* @returns {number[]} corrected bird count data
* @returns {void} should not return anything
*/
export function fixBirdCountLog(birdsPerDay) {
throw new Error('Please implement the fixBirdCountLog function');
105 changes: 78 additions & 27 deletions exercises/concept/bird-watcher/bird-watcher.spec.js
Original file line number Diff line number Diff line change
@@ -1,79 +1,130 @@
import { describe, expect, test } from '@jest/globals';
import { birdsInWeek, fixBirdCountLog, totalBirdCount } from './bird-watcher';

const customInspectSymbol = Symbol.for('nodejs.util.inspect.custom');
const customLogSymbol = Symbol.for('exercism.javascript.util.log');

// Follow the instructions in case you are stuck on "list.method is not a function"
class CountingReport {
constructor(counts) {
// Enables array[index]
counts.forEach((count, index) => {
this[index] = count;
});

// Enables .length
this.length = counts.length;
}

// Log value in non-upgraded environments
toString() {
return arrayOf(this).toString();
}

// Overrides logging in node (ie. students working locally)
[customInspectSymbol]() {
return `Seen birds per day: ${arrayOf(this)}`;
}

// Overrides log overrides in web environment (ie. students working in editor)
[customLogSymbol]() {
return `Seen birds per day: ${arrayOf(this)}`;
}
}

function report(...values) {
return new CountingReport(values);
}

function arrayOf(countingReport) {
return Array.from(
{ length: countingReport.length },
(_, i) => countingReport[i],
);
}

function randomArray(length) {
return Array.from({ length }, () => Math.floor(Math.random() * 8));
}

describe('totalBirdCount', () => {
test('calculates the correct total number of birds', () => {
const birdsPerDay = [9, 0, 8, 4, 5, 1, 3];
const birdsPerDay = report(9, 0, 8, 4, 5, 1, 3);
expect(totalBirdCount(birdsPerDay)).toBe(30);
});

test('works for a short bird count list', () => {
const birdsPerDay = [2];
const birdsPerDay = report(2);
expect(totalBirdCount(birdsPerDay)).toBe(2);
});

test('works for a long bird count list', () => {
// prettier-ignore
const birdsPerDay = [2, 8, 4, 1, 3, 5, 0, 4, 1, 6, 0, 3, 0, 1, 5, 4, 1, 1, 2, 6];
const birdsPerDay = report(
2, 8, 4, 1, 3, 5, 0, 4, 1, 6, 0, 3, 0, 1, 5, 4, 1, 1, 2, 6
);

expect(totalBirdCount(birdsPerDay)).toBe(57);
});
});

describe('birdsInWeek', () => {
test('calculates the number of birds in the first week', () => {
const birdsPerDay = [3, 0, 5, 1, 0, 4, 1, 0, 3, 4, 3, 0, 8, 0];
const birdsPerDay = report(3, 0, 5, 1, 0, 4, 1, 0, 3, 4, 3, 0, 8, 0);
expect(birdsInWeek(birdsPerDay, 1)).toBe(14);
});

test('calculates the number of birds for a week in the middle of the log', () => {
// prettier-ignore
const birdsPerDay = [4, 7, 3, 2, 1, 1, 2, 0, 2, 3, 2, 7, 1, 3, 0, 6, 5, 3, 7, 2, 3];
const birdsPerDay = report(4, 7, 3, 2, 1, 1, 2, 0, 2, 3, 2, 7, 1, 3, 0, 6, 5, 3, 7, 2, 3);
expect(birdsInWeek(birdsPerDay, 2)).toBe(18);
});

test('works when there is only one week', () => {
const birdsPerDay = [3, 0, 3, 3, 2, 1, 0];
const birdsPerDay = report(3, 0, 3, 3, 2, 1, 0);
expect(birdsInWeek(birdsPerDay, 1)).toBe(12);
});

test('works for a long bird count list', () => {
const week21 = [2, 0, 1, 4, 1, 3, 0];
const birdsPerDay = randomArray(20 * 7)
.concat(week21)
.concat(randomArray(10 * 7));
const week21 = report(2, 0, 1, 4, 1, 3, 0);
const birdsPerDay = report(
...randomArray(20 * 7)
.concat(arrayOf(week21))
.concat(randomArray(10 * 7)),
);

expect(birdsInWeek(birdsPerDay, 21)).toBe(11);
});
});

describe('fixBirdCountLog', () => {
test('returns a bird count list with the corrected values', () => {
const birdsPerDay = [3, 0, 5, 1, 0, 4, 1, 0, 3, 4, 3, 0];
const birdsPerDay = report(3, 0, 5, 1, 0, 4, 1, 0, 3, 4, 3, 0);
const expected = [4, 0, 6, 1, 1, 4, 2, 0, 4, 4, 4, 0];
expect(fixBirdCountLog(birdsPerDay)).toEqual(expected);
});

test('does not create a new array', () => {
const birdsPerDay = [2, 0, 1, 4, 1, 3, 0];
fixBirdCountLog(birdsPerDay);

// This checks that the same object that was passed in is returned.
// https://jestjs.io/docs/expect#tobevalue
expect(Object.is(fixBirdCountLog(birdsPerDay), birdsPerDay)).toBe(true);
expect(arrayOf(birdsPerDay)).toEqual(expected);
});

test('works for a short bird count list', () => {
expect(fixBirdCountLog([4, 2])).toEqual([5, 2]);
const birdsPerDay = report(4, 2);
fixBirdCountLog(birdsPerDay);

expect(arrayOf(birdsPerDay)).toEqual([5, 2]);
});

test('works for a long bird count list', () => {
// prettier-ignore
const birdsPerDay = [2, 8, 4, 1, 3, 5, 0, 4, 1, 6, 0, 3, 0, 1, 5, 4, 1, 1, 2, 6];
const birdsPerDay = report(
2, 8, 4, 1, 3, 5, 0, 4, 1, 6, 0, 3, 0, 1, 5, 4, 1, 1, 2, 6
);

// prettier-ignore
const expected = [3, 8, 5, 1, 4, 5, 1, 4, 2, 6, 1, 3, 1, 1, 6, 4, 2, 1, 3, 6];
expect(fixBirdCountLog(birdsPerDay)).toEqual(expected);
const expected = [
3, 8, 5, 1, 4, 5, 1, 4, 2, 6, 1, 3, 1, 1, 6, 4, 2, 1, 3, 6
]

fixBirdCountLog(birdsPerDay);
expect(arrayOf(birdsPerDay)).toEqual(expected);
});
});

function randomArray(length) {
return Array.from({ length: length }, () => Math.floor(Math.random() * 8));
}