Skip to content

Add baffling-birthdays exercise - #779

Open
resu-xuniL wants to merge 8 commits into
exercism:mainfrom
resu-xuniL:baffling-birthdays
Open

Add baffling-birthdays exercise#779
resu-xuniL wants to merge 8 commits into
exercism:mainfrom
resu-xuniL:baffling-birthdays

Conversation

@resu-xuniL

Copy link
Copy Markdown
Contributor

Add baffling-birthdays exercice to track.
I change difficulty from 1 to 4.

Hope everything is correct.

float with bash !
I increase the tolerance for the exercice with 10 and 23 people because, after multiple runs (many time consuming), sometimes one or the other fail when checking only respectively 11|12|13 and 50|51|52.
or might be another way to do it more precisely ?

The other option is to increase the number of runs, but this is very time consuming in bash! (set now at 1000)
maybe I can try to parallelize the computings? or creating a file would help?

I got these result while debbuging :

   (from function `assert_output' in file bats-extra.bash, line 394,
    in test file baffling_birthdays.bats, line 162)
     `assert_output $expect' failed
   
   -- output differs --
   expected : 11.694818
   actual   : 12.70
   --
   
 ✗ estimated probability of at least one shared birthday -> among twenty-three people
   (from function `assert_output' in file bats-extra.bash, line 394,
    in test file baffling_birthdays.bats, line 170)
     `assert_output $expect' failed
   
   -- output differs --
   expected : 50.729723
   actual   : 51.10
   --
   
 ✗ estimated probability of at least one shared birthday -> among seventy people
   (from function `assert_output' in file bats-extra.bash, line 394,
    in test file baffling_birthdays.bats, line 178)
     `assert_output $expect' failed
   
   -- output differs --
   expected : 99.915958
   actual   : 99.90
   --```
---

Reviewer Resources:

[Track Policies](https://github.com/exercism/bash/blob/master/POLICIES.md)

Comment thread exercises/practice/baffling-birthdays/.meta/example.sh Outdated
Comment thread exercises/practice/baffling-birthdays/.meta/example.sh Outdated
Comment thread exercises/practice/baffling-birthdays/baffling_birthdays.bats Outdated
Comment thread exercises/practice/baffling-birthdays/baffling_birthdays.bats Outdated
Comment thread exercises/practice/baffling-birthdays/baffling_birthdays.bats Outdated
Comment thread exercises/practice/baffling-birthdays/baffling_birthdays.bats Outdated
Comment thread exercises/practice/baffling-birthdays/.meta/example.sh Outdated
@resu-xuniL

resu-xuniL commented Jun 12, 2026

Copy link
Copy Markdown
Contributor Author

23 persons test failed again...
I'll work on it. Any suggestions are welcome! ^^
it passed just before the this test ...

Comment thread exercises/practice/baffling-birthdays/baffling_birthdays.bats Outdated
@IsaacG

IsaacG commented Jun 12, 2026

Copy link
Copy Markdown
Member

Geez... 23 persons test failed again... I'll work on it tomorrow. Any suggestions are welcome! ^^ it passed just before the this test ...

You can try doubling your runs from 1k to 2k. You can try widening the acceptable probability range.

@resu-xuniL
resu-xuniL force-pushed the baffling-birthdays branch from f401a42 to a95d347 Compare June 13, 2026 10:26
@resu-xuniL

resu-xuniL commented Jun 13, 2026

Copy link
Copy Markdown
Contributor Author

OK, it passes 6 times in a row (with this one) so far...
Thank you for your help!
(with runs at 1500)

@resu-xuniL
resu-xuniL requested a review from IsaacG June 13, 2026 10:59
Comment thread exercises/practice/baffling-birthdays/.meta/example.sh Outdated
Comment thread exercises/practice/baffling-birthdays/baffling_birthdays.bats Outdated
Comment thread exercises/practice/baffling-birthdays/baffling_birthdays.bats Outdated
Comment thread exercises/practice/baffling-birthdays/baffling_birthdays.bats Outdated
Comment thread exercises/practice/baffling-birthdays/baffling_birthdays.bats Outdated
@resu-xuniL
resu-xuniL force-pushed the baffling-birthdays branch from a95d347 to d01f64f Compare June 14, 2026 10:03
@resu-xuniL

resu-xuniL commented Jun 14, 2026

Copy link
Copy Markdown
Contributor Author

It passed 4 times in a row before i push this, and now it failed for 10 and 23 people tests!
shall i increase back the tolerence (i decreased them)? or increase the runs to 3k ?

(in the php track, I ran it 10k ... but in bash it would take so much time !!)

@resu-xuniL
resu-xuniL force-pushed the baffling-birthdays branch 6 times, most recently from b77a468 to 1d4dfd3 Compare June 14, 2026 12:08
@resu-xuniL

Copy link
Copy Markdown
Contributor Author

re-increased tolerance for 23 people test.

@IsaacG

IsaacG commented Jun 14, 2026

Copy link
Copy Markdown
Member

(in the php track, I ran it 10k ... but in bash it would take so much time !!)

How much time is too much time? How slow is 3k? 4k?

If it takes more than, say, 5 seconds, we probably want to widen the tolerance.

Comment thread exercises/practice/baffling-birthdays/.meta/example.sh Outdated
Comment thread exercises/practice/baffling-birthdays/.meta/example.sh Outdated
Comment thread exercises/practice/baffling-birthdays/.meta/example.sh Outdated
Comment thread exercises/practice/baffling-birthdays/baffling_birthdays.bats Outdated
Comment thread exercises/practice/baffling-birthdays/baffling_birthdays.bats Outdated
@resu-xuniL

resu-xuniL commented Jun 14, 2026

Copy link
Copy Markdown
Contributor Author

(in the php track, I ran it 10k ... but in bash it would take so much time !!)

How much time is too much time? How slow is 3k? 4k?

If it takes more than, say, 5 seconds, we probably want to widen the tolerance.

it was about 20+ minutes for 2k - 3k before modifications...

@resu-xuniL
resu-xuniL force-pushed the baffling-birthdays branch from 1d4dfd3 to f4268c2 Compare June 14, 2026 15:04
Comment thread exercises/practice/baffling-birthdays/baffling_birthdays.bats Outdated
Comment thread exercises/practice/baffling-birthdays/baffling_birthdays.bats Outdated
Comment thread exercises/practice/baffling-birthdays/baffling_birthdays.bats Outdated
Comment thread exercises/practice/baffling-birthdays/baffling_birthdays.bats Outdated
@glennj

glennj commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

Regarding the slowness, you'll get must faster performance by using the builtin $RANDOM variable instead of calling out to shuf

# return a random number in the range 0 <= n < $1
random_int() {
    echo $(( RANDOM % $1 ))
}
february_days=$(( 1 + $(random_int 28) ))

With group_size = 10 and runs = 5000, you're calling shuf 150,000 times and date 50,000 times.

Comment thread exercises/practice/baffling-birthdays/.meta/example.sh Outdated
Comment thread exercises/practice/baffling-birthdays/.meta/example.sh Outdated
@resu-xuniL
resu-xuniL force-pushed the baffling-birthdays branch 4 times, most recently from 11fe39c to 8bffcb9 Compare June 14, 2026 19:23
@resu-xuniL

Copy link
Copy Markdown
Contributor Author

Results so far (runs are set at 5k):

11 50 99
11 51 99
11 50 99
10 50 99
11 51 99
12 52 99
11 50 99
11 51 100
12 50 99
11 49 99
11 50 100
11 50 100
11 50 99

very rare are the 9 or the 13
very rare are the 49 or the 52
never seen is the 98

--

To prevent the failure, maybe we could add this condition in the .bats file (this would be very unlucky if the run fails twice in a row!)

@test "estimated probability of at least one shared birthday -> among ten people" {
    [[ $BATS_RUN_SKIPPED == "true" ]] || skip
    # The expected probability is 11.694818
    run bash baffling_birthdays.sh estimated_probability_of_share_birthday 10
    assert_success
    if ! assert_between 10 12; then
        run bash baffling_birthdays.sh estimated_probability_of_share_birthday 10
        assert_success
        assert_between 10 12
    fi
}

@test "estimated probability of at least one shared birthday -> among twenty-three people" {
    [[ $BATS_RUN_SKIPPED == "true" ]] || skip
    # The expected probability is 50.729723
    run bash baffling_birthdays.sh estimated_probability_of_share_birthday 23
    assert_success
    if ! assert_between 49 51; then
        run bash baffling_birthdays.sh estimated_probability_of_share_birthday 23
        assert_success
        assert_between 49 51
    fi
}

@test "estimated probability of at least one shared birthday -> among seventy people" {
    [[ $BATS_RUN_SKIPPED == "true" ]] || skip
    # The expected probability is 99.915958
    run bash baffling_birthdays.sh estimated_probability_of_share_birthday 70
    assert_success
    if ! assert_between 98 100; then
        run bash baffling_birthdays.sh estimated_probability_of_share_birthday 70
        assert_success
        assert_between 98 100
    fi
}

I'm testing this ATM, and it seems to work good.

@IsaacG

IsaacG commented Jun 18, 2026

Copy link
Copy Markdown
Member

Note, the tests need to run in under 20s max. I'd recommend trying to get them in under 5s.

@resu-xuniL

Copy link
Copy Markdown
Contributor Author

well, then, I can't see how to do... unless removing the tests which check for "estimated probability of at least one shared birthday"

@IsaacG

IsaacG commented Jun 18, 2026

Copy link
Copy Markdown
Member

This is a bit of a hacky solution, but it is valid and fast. Roughly 0.9s to run 5000 checks, each check looking for a collision with up to 70 random values.

#!/bin/bash

check () {
    local -a hit
    for (( j = 0; j < $1; j++ )); do
        day=$((RANDOM % 365))
        (( hit[day]++ == 0 )) || return 1
    done
}

for (( i = 0; i < 5000; i++ )); do
    check 70 || (( hit++ ))
done

echo $hit $(( hit / 50 ))

It bypasses the whole "generate 70 dates" and goes straight to the math side: generate 70 values from a space of 365 and look for a collision.

@resu-xuniL

resu-xuniL commented Jun 18, 2026

Copy link
Copy Markdown
Contributor Author

edit: Isn't the point to test the whole "generated 70 dates" ?

@glennj

glennj commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

I conclude that bash cannot be used to solve this with nested loops. It's just too slow.

You might want to investigate https://en.wikipedia.org/wiki/Birthday_problem#Approximations

@glennj

glennj commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

I had a conversation with Claude about it. Turns out the bottlenecks are the number of subshells. (The "200 subshells" you see are while I had reduced runs=2000)

Summary

The performance bottleneck in the original estimated_probability_of_share_birthday was massive subshell spawning — 200 iterations × multiple subprocess forks per iteration = thousands of process forks.

Root Causes Eliminated

Problem Original Optimized
random_int helper $(random_int N) — subshell per call Inlined: RANDOM % N directly in arithmetic
printf formatting $(printf '%d-%02d-%02d' ...) — subshell per date Manual zero-padding with &&/|| in-process (Glenn: used printf -v)
random_birthdates call Process substitution < <(random_birthdates ...) — 200 subshells Inlined loop via _make_random_birthdate (sets global _random_birthday)
shared_birthday call Command substitution "$(shared_birthday ...)" — 200 subshells Inlined check via _check_shared_birthday (sets global _has_shared)

Design Pattern

Two helper functions use output globals instead of stdout to avoid subprocess forks:

  • _make_random_birthdate → sets $_random_birthday
  • _check_shared_birthday → sets $_has_shared

The public random_birthdates and shared_birthday functions remain unchanged for compatibility with other test cases.

Here's a version that uses "private" functions to write global variables as the data-passing mechanism: https://gist.github.com/glennj/4e8a3ab4a9942b798ace0f8dba0bb30b

The test suite runs in about 7 seconds on my machine.

@IsaacG

IsaacG commented Jun 25, 2026

Copy link
Copy Markdown
Member

If this exercise requires hoops to solve in under 5s, I propose we add it to the foregone list.

@resu-xuniL

Copy link
Copy Markdown
Contributor Author

I don't think this is 'hoops', this is just that I need learning more and more :)

@resu-xuniL

resu-xuniL commented Jun 25, 2026

Copy link
Copy Markdown
Contributor Author

new stats with runs=2k

      1 x 9
     12 x 10
     65 x 11
     40 x 12
      8 x 13

      1 x 47
      5 x 48
     15 x 49
     28 x 50
     25 x 51
     11 x 52
      3 x 53

@IsaacG

IsaacG commented Jun 25, 2026

Copy link
Copy Markdown
Member

The fact that this requires so much work and learning to get working in a reasonable amount of time indicates to me that this may not be a great fit for the bash track 😄

Thoughts on marking this foregone, @glennj ?

@glennj

glennj commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

The fact that this requires so much work and learning to get working in a reasonable amount of time indicates to me that this may not be a great fit for the bash track 😄

Thoughts on marking this foregone, @glennj ?

We have:

  1. a monte-carlo approach that takes an unreasonable amount of time,
  2. a monte-carlo approach that is reasonable, and
  3. non-randomized mathematical approaches (not demonstrated here, but https://exercism.org/tracks/lua/exercises/baffling-birthdays/solutions has some)

I think we can proceed. We'll probably see monstly 1 and 3 submitted.

An instructions.append.md file would be useful to gently steer people along. Approaches articles might help too.

@IsaacG

IsaacG commented Jun 25, 2026

Copy link
Copy Markdown
Member

I think we can proceed. We'll probably see monstly 1 and 3 submitted.

An instructions.append.md file would be useful to gently steer people along. Approaches articles might help too.

Solutions that take long to run will fail the test runner. The approaches article can only be viewed after passing tests.

We'd want to provide a fair bit of guidance in the append file to help students get this to pass on the test runner.

@glennj

glennj commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

How about this approach:

  1. add "status": "wip" to the exercise blob in config.json and we merge this PR.
  2. then we work on a new PR to add .docs/instructions.append.md and change the status to "beta".

@resu-xuniL resu-xuniL changed the title Add baffling-birthdays exercice Add baffling-birthdays exercise Jul 23, 2026
@IsaacG

IsaacG commented Aug 6, 2026

Copy link
Copy Markdown
Member

What's the status on this PR?

@resu-xuniL resu-xuniL closed this Sep 12, 2026
@resu-xuniL
resu-xuniL deleted the baffling-birthdays branch September 12, 2026 21:22
@resu-xuniL
resu-xuniL restored the baffling-birthdays branch September 12, 2026 21:46
@resu-xuniL resu-xuniL reopened this Sep 12, 2026
Comment thread config.json Outdated
Co-authored-by: Glenn Jackman <glenn.jackman@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants