-1

I am doing the following programming exercise: No musical. The statement is:

In my school, a grand musical is performed every 4 years. This means that every student who comes to this school will get to see a musical performed exactly once in their 4-year stay. This is not always the case in other schools though.

For a given duration of time, an interval after which a musical is performed, and the duration of class enrolment, can you determine how many class-years did not get to have a musical performed in their school? A musical is always performed for the start_class.

Example:

no_musical(start_class = 2000, end_class = 2010,
musical_performed_every = 5, duration_of_enrolment_in_school = 3) = 4

Explanation: Only the class of 2000 gets to see the musical performed in 2000. The next musical will be in 2005 so only the class of 2003 in their last year, 2004 in their second year, and 2005 in their first year, get to see it. The next musical will be in 2010 so only the class of 2008, 2009 and 2010 get to see it. This leaves us with the class of 2001, 2002, 2006 and 2007 who never get to see a musical, a total of 4 classes :(

TO NOTE:

In this kata, if duration of enrolment in school is, say, 4 years, members of a class that starts in 2000 will graduate in 2003, not

2004. Their years of enrolment in the school would be 2000, 2001, 2002 and 2003. (In the standard way that we are used to the term 'class of', they would be the class of 1999 as they would graduate in 2003, but we do not do that here) As seen in the example, the range is end-inclusive. The last class should also be accounted for. Very minor note, we assume all the students in the school will actually go to watch the musical - not that it matters for this kata anyway. That said, I am not really a musical person :-(

5 sample tests, 50 randomized tests.

Good luck.

We have written the following Python code:

import math
def no_musical(start_class, end_class, musical_performed_every, enrolment_duration):
    print("start_class: ",start_class)
    print("end_class: ",end_class)
    print("musical_performed_every: ",musical_performed_every)
    print("enrolment_duration: ",enrolment_duration)
    if(start_class>=end_class): return 0
    if(musical_performed_every==0): return end_class-start_class+1
    if(enrolment_duration>musical_performed_every): return 0
    allCourses=end_class-start_class
    print("allCourses: ",allCourses)
    numberOfMusicals=math.ceil((allCourses)/musical_performed_every)
    print("numberOfMusicals: ",numberOfMusicals)
    coursesWhichSeeMusical=numberOfMusicals*enrolment_duration
    print("coursesWhichSeeMusical: ",coursesWhichSeeMusical)
    coursesWhichNotSeeMusical=allCourses-coursesWhichSeeMusical
    return 0 if coursesWhichNotSeeMusical<0 else coursesWhichNotSeeMusical

And there are three tests where our code does not give the expected output:

# Use test.describe (or Test.describe) to describe your test suite
test.describe("Musicals")

# What if the start and end year are the same?
test.assert_equals(no_musical(2000,2000,100,3), 0)

# What if the school does not do musicals?
test.assert_equals(no_musical(2000,3000,0,50), 1001)

# What if all the students get to see musicals?
test.assert_equals(no_musical(2000,2020,2,4), 0)

# But are you doing it right though?
test.assert_equals(no_musical(2000, 3000, 5, 2), 600)

test.assert_equals(no_musical(2000, 2010, 5, 3), 4)

#our code fails in this test, by 1 year
test.assert_equals(no_musical(2910, 3505, 4, 3), 149)

#our code fails in this test, by 2 years
test.assert_equals(no_musical(2483, 3309, 18, 2), 736)

#our code fails in this test, by 4 years
test.assert_equals(no_musical(2969, 3508, 17, 4), 415)

We observe in the last three tests the following trace:

start_class: 2910 end_class: 3505 musical_performed_every: 4 enrolment_duration: 3 allCourses: 595 numberOfMusicals: 149 coursesWhichSeeMusical: 447 148 should equal 149

start_class: 2483 end_class: 3309 musical_performed_every: 18 enrolment_duration: 2 allCourses: 826 numberOfMusicals: 46 coursesWhichSeeMusical: 92 734 should equal 736

start_class: 2969 end_class: 3508 musical_performed_every: 17 enrolment_duration: 4 allCourses: 539 numberOfMusicals: 32 coursesWhichSeeMusical: 128 411 should equal 415

We have read:

How could we debug this code?‽

Yone
  • 2,064
  • 5
  • 25
  • 56
  • 2
    Please read [Why is "Can someone help me?" not an actual question](https://meta.stackoverflow.com/questions/284236/why-is-can-someone-help-me-not-an-actual-question/284237#284237) – Brian61354270 Mar 13 '20 at 18:07
  • 1
    We could insert `print` statements after each `if` (with a useful debugging text) so we'd exactly see on what condition those failing cases fire. – Jongware Mar 13 '20 at 18:12
  • Please see [tour], [ask], [help/on-topic], and https://ericlippert.com/2014/03/05/how-to-debug-small-programs/. – AMC Mar 14 '20 at 03:19

2 Answers2

0

Logically the question literally translates to the following code, which iterates through all the class years and counts the number of those whose enrollment years are not in any of the years where a musical is performed:

def no_musical(start_class, end_class, musical_performed_every, enrollment_duration):
    return sum(
        not musical_performed_every or
        all(
            year + i not in range(start_class, end_class + 1, musical_performed_every) 
            for i in range(enrollment_duration)
        ) for year in range(start_class, end_class + 1)
    )

which passes the following tests:

assert no_musical(2000,2000,100,3) == 0
assert no_musical(2000,3000,0,50) == 1001
assert no_musical(2000,2020,2,4) == 0
assert no_musical(2000, 3000, 5, 2) == 600
assert no_musical(2000, 2010, 5, 3) == 4
assert no_musical(2483, 3309, 18, 2) == 736
assert no_musical(2969, 3508, 17, 4) == 415

but not this one:

assert no_musical(2910, 3505, 4, 3) == 149

since no_musical(2910, 3505, 4, 3) would return 151.

I would question if this particular test case has the right expected value.

blhsing
  • 91,368
  • 6
  • 71
  • 106
0

The number of musicals performed should be the number of class years divided by the frequency of musical performances, rounded down, not up, so change:

numberOfMusicals=math.ceil((allCourses)/musical_performed_every)

to:

numberOfMusicals=math.floor((allCourses)/musical_performed_every)

or simply:

numberOfMusicals = allCourses // musical_performed_every

and you would pass all the tests except no_musical(2910, 3505, 4, 3) == 149, as no_musical(2910, 3505, 4, 3) returns 151 rather than the expected 149. But since this matches the result of my other answer, I would question if this particular test case has the right expected value to begin with.

blhsing
  • 91,368
  • 6
  • 71
  • 106