15
\$\begingroup\$

Help PPCG Claus Deliver his Presents

Overview

PPCG Claus is running hella late delivering his gifts because nowadays we have so many odd little kiddos out there. This makes it much harder for PPCG Claus to get all the presents to the correct place. Your challenge is to help him delvier his presents correctly.

The Complexity

Given a list of capitalized first names representing the kids he's supposed to deliver to and a list of presents represented by numbers, you must figure out how to distribute the presents among said children. Of course there's a catch though....

Nowadays kids are getting picky, if the kiddo is an odd fellow (first initial is ASCII-code odd) he wants an odd gift! If he's an even fellow (first initial is ASCII-code even) he obviously must be given an even one! Any child divisible by 3, however, is a naughty, naughty lad, so PPCG Claus must completely ignore them to make them behave next year. To consider his route a success he must deliver all presents to all children who deserve them and must not give any one child too many presents. If any child gets 3+ more presents than his or her peers, he risks becoming a naughty child next year, and that's just not right! Also, if any good child were to receive a present when another good child didn't, that also would turn that child evil.

Example

The kids are as follows:

Kids = ["Amy", "Betty", "Clyde", "Dave", "Francine"] = [A,B,C,D,F] = [65,66,67,68,70]

  • Betty is the bane of humanity, clearly in cahoots with the number 3.
  • Amy and Clyde have been weirdos since birth and would hate to receive even presents.
  • Dave and Francine are normal, even, kids; they should only receive even presents!

The presents are as follows:

Presents = [1,2,3,4,5,6,7,8,9,10,11,12,13,14]

One possible output would be:

[
    ['Amy',[1,3,5]],
    ['Betty',[]],
    ['Clyde',[7,9,11,13]],
    ['Dave',[2,4,6,8]],
    ['Francine',[10,12,14]]
]

Exception Scenarios

However, just because PPCG Claus is ready and willing, doesn't mean PPCG Claus can. Here's a list of exception scenarios where you must break the bad news to PPCG Claus with a message of:

PPCGmas is cancelled!

The following scenarios will result in Christmas being cancelled:

  • There are no children.
    • [],[1,2,3] - Wellp, they ded.
  • There are no good children.
    • ["Betty"],[1,2,3] - Seriously, screw Betty.
  • There are no presents, or less presents than good children.
    • ["Amy","Charles"],[] - One or more would receive no presents.
    • ["Amy","Charles"],[1] - One or more would receive no presents.
  • There are not odd/even presents to satisfy all good children.
    • ["Amy","Dave"],[2,4,6] - Amy is screwed over.

Here's a list of scenarios that shouldn't affect PPCGmas:

  • Leftover Presents (All children should receive the maximal amount of presents).
    • ["Amy","Dave"],[2,4,6,8,10,12,14,7,9] = [["Amy",[7,9]],["Dave",[2,4,6,8]]]

Main Rules Reiterated

  1. Good children are either even or odd, based on their first initial.
  2. Bad children have a first initial wholly divisible by 3.
  3. All good children must receive at least one present.
  4. No good child is to receive greater than 2 presents more than any other good child.
  5. If there are to be leftover presents you must maximally distribute them, without violating 4.
  6. Bad children must receive no presents at all.
  7. If ANY of these is violated, you must output PPCGmas is cancelled!, exactly.

I/O Format Requirements

  • The 1st input must be an array/list/comma-delimited string of full names, not just the first initial.
  • The 2nd input must be a array/list/comma-delimited string of positive integers.
  • The output may be any denotation of how you distributed the presents that makes sense; or PPCGmas is Cancelled!.

Winning Criterion:

TL;DR: Betty is a jerk, don't compete.

\$\endgroup\$
2
  • \$\begingroup\$ I don't understand, in the example, why doesn't Betty get 3? EDIT: If one should "screw Betty", why is she in the challenge at all? \$\endgroup\$ Dec 16, 2016 at 18:31
  • \$\begingroup\$ @SeeOneRhino B = 66, 66 % 3 = 0, 66 is divisible by 0, Betty is naughty. \$\endgroup\$ Dec 16, 2016 at 19:49

4 Answers 4

4
\$\begingroup\$

APL, 171 bytes

{D←{⍵=1:⊂⍺⋄0~⍨¨↓⍵↑⍉↑⍺⊂⍨1=⍵|⍳⍴⍺}⋄e←⍺~o←⍺/⍨2|⍺⋄(0=≢G)∨0∊≢¨P←P↑⍨¨(2+⌊/R)⌊R←≢¨P←(o D≢O),e D≢E←G~O←G/⍨2|⎕A⍳⊃¨G←⍵/⍨×3|⊃∘⎕UCS¨⍵:'PPCGmas is cancelled!'⋄(O,E,B),[⍟4]P,(≢B←⍵~G)↑⊂⍬}

This takes the presents as the left argument, the children as the right argument, and returns a matrix where the first column contains the names of the children and the second column contains the presents they get.

Testcases:

      P←{D←{⍵=1:⊂⍺⋄0~⍨¨↓⍵↑⍉↑⍺⊂⍨1=⍵|⍳⍴⍺}⋄e←⍺~o←⍺/⍨2|⍺⋄(0=≢G)∨0∊≢¨P←P↑⍨¨(2+⌊/R)⌊R←≢¨P←(o D≢O),e D≢E←G~O←G/⍨2|⎕A⍳⊃¨G←⍵/⍨×3|⊃∘⎕UCS¨⍵:'PPCGmas is cancelled!'⋄(O,E,B),[⍟4]P,(≢B←⍵~G)↑⊂⍬}
      (⍳14) P 'Amy' 'Betty' 'Clyde' 'Dave' 'Francine'
┌────────┬─────────┐
│Amy     │1 5 9 13 │
├────────┼─────────┤
│Clyde   │3 7 11   │
├────────┼─────────┤
│Dave    │2 6 10 14│
├────────┼─────────┤
│Francine│4 8 12   │
├────────┼─────────┤
│Betty   │         │
└────────┴─────────┘
      1 2 3 P ⍬
PPCGmas is cancelled!
      1 2 3 P ⊂'Betty'
PPCGmas is cancelled!
      ⍬ P 'Amy' 'Charles'
PPCGmas is cancelled!
      (,1) P 'Amy' 'Charles'
PPCGmas is cancelled!
      2 4 6 P 'Amy' 'Dave'
PPCGmas is cancelled!
      2 4 6 8 10 12 14 7 9 P 'Amy' 'Dave'
┌────┬───────┐
│Amy │7 9    │
├────┼───────┤
│Dave│2 4 6 8│
└────┴───────┘

Ungolfed version here.

\$\endgroup\$
1
  • \$\begingroup\$ What's this "christmas" of which you speak in the ungolfed version :P? \$\endgroup\$ Dec 20, 2016 at 17:07
4
\$\begingroup\$

JavaScript (ES6), 525 492 454 453 bytes

-71 bytes thanks to @Guedes -1 bit thanks to @Jake Cobb

P=(K,p)=>{y='charCodeAt';n=(C)=>C[y](0)%3>0;N=(C)=>C[y](0)%3<1;E=(C)=>C[y](0)%2>0;O=(C)=>C[y](0)%2<1;f=(U)=>U%2<1;F=(U)=>U%2;M=(U,C)=>C%s==S;s=S=0;a=new Array();G='filter';e=p[G](f);o=p[G](F);J=K[G](n);r=J[G](O);L='length';i=J[G](E);s=r[L];for(S=0;S<r[L];S++){a.push([r[S],e[G](M)]);}s=i[L];for(S=0;S<i[L];S++){a.push([i[S],o[G](M)]);}K=K[G](N);for(S=0;S<K[L];S++){a.push(K[S],[]);}return(e[L]<r[L]||o[L]<i[L]||(r[L]+i[L])<1)?"PPCGmas is Cancelled!":a;}

Try it online !

Non-golfed version

Can be more golfed I think. I just did a litteral translation of the non-golfed version.

This is now shorter than the sum of the CharCode composing "santa" (115 + 97 + 110 + 116 + 97 = 535). Yeay

\$\endgroup\$
5
  • \$\begingroup\$ C[0] instead of C.charCodeAt(0) saves 11 bytes. Also, when a property repeats many times you can store its name like L='length', and use i[L] instead of i.length. \$\endgroup\$ Dec 19, 2016 at 14:55
  • 2
    \$\begingroup\$ By the way, welcome to PPCG!! \$\endgroup\$ Dec 19, 2016 at 14:56
  • \$\begingroup\$ Thank you for the advices ! :D. Well I've tried C[0] instead of C.charCodeAt(0) (modern firefox browser on repl.it) and it returns "PPCGmas is cancelled" on the first verification. As for the second, it works well, thanks for the Bytes :) \$\endgroup\$
    – ColdK
    Dec 19, 2016 at 15:41
  • 1
    \$\begingroup\$ This has the same bug as my original answer where it fails if the good children are all even or all odd, try this test: P(["Amy", "Betty", "Clyde"],[1,2,3,4,5,6,7,8,9,10,11,12,13,14]); \$\endgroup\$
    – Jake Cobb
    Dec 20, 2016 at 14:44
  • \$\begingroup\$ That's true ! It was because I used "&&" instead of "+" in one of the last verification. Thanks to you this problem is now fixed, and I gained one byte. \$\endgroup\$
    – ColdK
    Dec 20, 2016 at 14:57
4
\$\begingroup\$

Python 2, 334 355 354 bytes

k,p=input()
z=zip
l=len
e=[];o=[];g=[];b=[];q=[];r=[]
for x in k:[g,b][ord(x[0])%3<1]+=x,
for x in g:[e,o][ord(x[0])&1]+=x,
for x in p:[q,r][x&1]+=x,
v=l(e)
w=l(o)
t=v and l(q)/v
u=w and l(r)/w
if u:t=min(t,u+2)
if t:u=min(u,t+2)
if l(g)*(t or v<1)*(u or w<1)<1:exit('PPCGmas is cancelled!')
print z(e,z(*[iter(q)]*t))+z(o,z(*[iter(r)]*u))+z(b,[()]*l(b))

Lost 21 bytes to handle case of only-even or only-odd children.

Saved 1 byte thanks to @TuukkaX.

\$\endgroup\$
2
  • \$\begingroup\$ Doesn't work, ord('A')%3==0 is False but 1-ord('A')%3 is -1. \$\endgroup\$
    – Jake Cobb
    Jan 10, 2017 at 18:11
  • \$\begingroup\$ Oh yes, you're right. My apologies. %3<1 should work. \$\endgroup\$
    – Yytsi
    Jan 10, 2017 at 20:42
2
\$\begingroup\$

Javascript (ES6), 218 216 Bytes

(a,b)=>{c={};a.forEach(d=>c[d]=[]);e=f=0;while(!e){e=g=1;a.forEach(h=>(j=h.charCodeAt())%3?(k=b.findIndex(l=>l%2==j%2))<0?g=0:c[h][f+1]?0:e=0&c[h].push(b.splice(k,1)[0]):0);f+=!e&g}return f?c:"PPCGmas is cancelled!"}

The output (if it's not the error string) is an object whose keys are the children's names; the value is the array of presents that child receives.

Saved two bytes when I realized I had a pair of redundant parentheses.

Ungolfed version:

(names, gifts) => {
  
  // Initialize result. Set every child's gift array to empty
  var result = {};
  names.forEach(name =>
    result[name] = [];
  );
  
  // Initialize external loop values
  var done = false;
  var leastNumberOfPresentsAmongGoodChildren = 0;
  
  // Give the gifts
  while (!done) {
    
    // Initialize internal loop values
    done = true;
    var everyGoodChildGotGift = true;
    
    // Try to give at most one gift to every good child
    names.forEach(name => {
      var nameCode = name.charCodeAt(0);
      
      // Ignore bad children
      if ((nameCode % 3) != 0) {
        
        // Try to find an appropriate gift
        var giftIndex = gifts.findIndex(gift => (gift % 2) == (nameCode % 2));
        
        // If there is no gift, set the flag
        if (giftIndex < 0)
          everyGoodChildGotGift = false;
        
        // Make sure we don't give too many gifts
        else if (result[name].length < leastNumberOfPresentsAmongGoodChildren + 2) {
          
          // Remove the gift from the gifts array (we can't give it again)
          var giftToGive = gifts.splice(giftIndex, 1)[0];
          
          // Give the gift to the child
          result[name].push(giftToGive);
          
          // If at least one child got a gift, try to give more gifts
          done = false;
        }
      }
    }); // end forEach
    
    // If we're done, that means we couldn't give a gift to any good child
    if (done)
      everyGoodChildGotGift = false;
    
    // If every good child got a gift, then increase the count
    if (everyGoodChildGotGift)
      leastNumberOfPresentsAmongGoodChildren++;
    
  } // end while
  
  // If every good child gets at least one gift, return who gets what
  if (leastNumberOfPresentsAmongGoodChildren != 0)
    return result;
  else
    return "PPCGMas is cancelled!"; // IT'S ALL YOUR FAULT, BETTY. YOU'VE RUINED PPCGMAS.
}
\$\endgroup\$
2
  • \$\begingroup\$ Hi, Welcome to PPCG! Glad to see you seem to understand how posts are formatted. Happy Code-Golfing! \$\endgroup\$
    – ATaco
    Dec 20, 2016 at 23:48
  • \$\begingroup\$ @ATaco Thanks! I lurk \$\endgroup\$
    – Ian
    Dec 21, 2016 at 14:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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