9
\$\begingroup\$

An office (let's call it "The Office") is going to cut down on wasted time in 2019 by consolidating office birthday parties. Any two people with a birthday between Monday and Friday (inclusive) of the same week will be celebrated with a Shared Birthday Party some time that week. People whose birthdays fall on a Saturday or Sunday get no party at all.

Some people do not like sharing a birthday party with people who do not share their actual birthday. They will be Very Angry to have a Shared Birthday Party.

We are going to simulate an office and find the first week in which someone gets Very Angry about their Shared Birthday Party.

The Challenge

Write a program or function that outputs the first ISO week number for 2019 in which someone in a simulated office gets Very Angry about their Shared Birthday Party, subject to the following basic rules:

  • input an integer N > 1, which is the number of workers in the office.
  • the N birthdays themselves are distributed uniformly at random from Jan 1 to Dec 31 (ignore Feb 29).
  • but the working weeks for the purposes of determining Shared Birthday Parties are the 2019 ISO Week Dates, which are between 2019-W01-1 (2018-12-31) and 2019-W52-7 (2019-12-29). A new ISO week starts every Monday. (I think this is all you really need to know about ISO weeks for this challenge).
  • for the N people in the office, each has a 1/3 chance of having a Very Angry Shared Birthday Party personality type, so you'll have to simulate that too.
  • but they will not be angry if the party is shared with people who have the same birthday.
  • output the ISO week number (exact format for this is flexible as long as the week number is clear) for the first occurrence of a Very Angry person. If there are no angry people, you can output anything that isn't confused with an ISO week or the program can error out etc.

Some simplifying assumptions:

  • as I mentioned, ignore the February 29 issue completely (an unneeded complication)
  • ignore public holidays (this is an international community so our holidays will differ) and just assume the office is open on each weekday.

Rules

This is code-golf. Shortest answer in bytes for each language wins. Default loopholes forbidden.

Code explanations welcome.

Worked Examples

Contrived Example 1 with input N = 7. First and second columns are random as described in the rules (but not actually random here of course).

Angry Type
Person?    Birthday   ISO Week   Comment
================================================================================
   N       2018-12-31      W01   In the 2019 ISO week date year 
   Y       2018-12-31      W01   Same birthday, so no anger happens
   N       2019-02-05      W06   
   Y       2019-03-15      W11   No anger happens because other W11 b-day is a Saturday     
   N       2019-03-16      W11
   N       2019-09-08      W36   My birthday!
   Y       2019-12-30       -    Not in the 2019 ISO week date year

So no anger happens. The program or function can error out or output something not confused with an ISO week number.

Example 2 with N unspecified.

Angry Type
Person?    Birthday   ISO Week   Comment
================================================================================
   N       2019-01-19      W03   
   Y       2019-02-04      W06   
   N       2019-02-05      W06   No anger because not an angry person
  ...             ...      ...   (No angry people until...)
   Y       2019-03-12      W11   Very Angry Person!
   N       2019-03-14      W11   
  ...             ...      ...   ... 

The output would be W11 or something equivalent.

\$\endgroup\$
  • 3
    \$\begingroup\$ ... There is no 29th of February in 2019! Can you add a worked example, please? \$\endgroup\$ – Shaggy Jul 25 '18 at 21:23
  • \$\begingroup\$ What should the output be if no-one is "very angry"? This could pretty easily happen for small \$ N \$. \$\endgroup\$ – FryAmTheEggman Jul 25 '18 at 21:26
  • 4
    \$\begingroup\$ @Shaggy there could be people who work there whose birthday is February 29. I'm saying to just ignore that possibility since it just adds a pointless egde case IMO. \$\endgroup\$ – ngm Jul 25 '18 at 23:36
  • 1
    \$\begingroup\$ If there are no angry people, any suitable output that is not W01 to W52 or equivalent, or an error message, is fine. I'll edit the question to reflect this when I am off mobile. \$\endgroup\$ – ngm Jul 25 '18 at 23:39
  • 1
    \$\begingroup\$ Maybe it's me, but I rather have a shared birthday party than none at all. Rip all those who have their birthdays in the weekend. \$\endgroup\$ – Kevin Cruijssen Jul 26 '18 at 7:02
5
\$\begingroup\$

Python 2, 172 202 bytes

def f(n):
 D=set();A=[];R=randint
 while n:
	n-=1;w,d=R(1,52),R(1,5)
	if R(0,364)>104:D|={(w,d)};A+=[w]*(R(0,2)>1)
 return next((a for a in sorted(A)if[w for w,d in D].count(a)>1),0)
from random import*

Try it online!

oops! Missed a requirement; cost 30 bytes.

It is given by the OP that your birthday is not 29 February.

If your birthday is 30 December, it will not fall in any ISO week of 2019, so in any case you cannot be a Very Angry ISO week of 2019.

That leaves 364 other birthdays to consider you being Very Angry about. 104 of these fall on weekends when we have stipulated that you won't get Very Angry about it. So we only care about you 260/365 of the time; i.e., when R(0,364)>104 (randint's range is inclusive). Given that constraint, it is equiprobable that your weekday birthday falls in any of the 52 ISO weeks of 2019, and any weekday of that week; and, independently, that you are 1 in 3 likely to be a Very Angry person.

D is then a set of (weeknum,weekday) so that if a potentially Angry person shares an actual birthday, then there's no need to be Amgry unless there's yet another person having a birthday that week.

0 is returned if no Very Angry people manifest during any ISO 2019 week; otherwise, the ISO week number of the earliest meltdown is returned.

\$\endgroup\$
  • \$\begingroup\$ Shouldn't you also consider the edge case of December 31, 2019? \$\endgroup\$ – Charlie Jul 26 '18 at 7:26
  • 1
    \$\begingroup\$ @Charlie: Sure! But December 31 2018 is in the same ISO week 2019 as Jan 1 2019 thus would be a part of that "jealous party week", so it works out. \$\endgroup\$ – Chas Brown Jul 26 '18 at 7:30
  • \$\begingroup\$ I'm no Python expert, but I believe your answer fails to account for this: "but they will not be angry if the party is shared with people who have the same birthday." You still got my upvote though. \$\endgroup\$ – O.O.Balance Jul 31 '18 at 9:43
  • \$\begingroup\$ @O.O.Balance: Ooops! Missed that; amended! \$\endgroup\$ – Chas Brown Jul 31 '18 at 21:03
2
\$\begingroup\$

Jelly,  36 32  33 bytes

+1 byte to fix the 30-Dec edge-case I had not noticed (as pointed out by Chas Brown has in comments below the OP)

-4 thanks to Erik the Outgolfer (inline helper and use of outer product)

7R2<52×þFX)Ġị$,3XỊ¤€ṁ@\PṢ€Ḋ€Fḟ0Ḣ

A monadic link which yields an integer in \$[0,52]\$ where \$0\$ means no Very Angry people at all during the year and other outputs are ISO week numbers.

Try it online!

Or see this version which prints the weeks in which each person's birthday lies (0 for weekends) grouped up, then prints a same-ordered list of lists of whether those people are of the Very Angry type, and finally prints the result.

\$\endgroup\$
1
\$\begingroup\$

Java 8, 198 bytes

double r(){return Math.random();}

n->{int r=52,a[]=new int[r];for(;n-->0;)if(r()*364>104)++a[(int)(r()*r)];for(;++n<52;)r=r>51&a[n]>1&r()<1-5/Math.pow(5,a[n])&r()<1-Math.pow(2./3,a[n])?n:r;return r;}

Output is zero-based (0-51); a value of 52 indicates no Very Angry people. Try it online here.

Ungolfed:

double r() { return Math.random(); } // shortcut for Math.random(), saves a few bytes

n -> { // lambda taking an intger argument and returning an integer
    int r = 52, // this will hold the result; set to the value for "no Very Angry people" for now
    a[] = new int[r]; // array counting the people whose birthday lies in each week
    for(; n-- > 0; ) // for each person:
        if(r() * 364 > 104) // determine whether their birthday is on a weekday that is not the 30th of December ...
            ++a[(int) (r() * r)]; // ... only if so, increment the counter for a random ISO week
    for(; ++n < 52; ) // loop through the weeks; n is -1 before the loop
        r = r > 51   // if r is still the default ...
          & a[n] > 1 // ... and there is more than one person with a birthday that week ...
          & r() < 1 - 5/Math.pow(5, a[n]) // ... and at least two people have a different birthday ...
          &r() < 1 - Math.pow(2./3, a[n]) // ... and at least one person has the Very Angry personality type ...
          ? n  // ... set the current week as the result ...
          : r; // ... otherwise leave it the same
    return r;  // return the result
}
\$\endgroup\$
  • \$\begingroup\$ Suggest 91>26 instead of 364>104 \$\endgroup\$ – ceilingcat yesterday

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.