19
\$\begingroup\$

After @MartinBüttner achieved exactly 10,000 reputation, we now have three full rows of 10k users on the users page! Now, since we're all programmers here, we like to automate things instead of doing them manually. Your challenge is to write a program to automatically congratulate new 10k users.

Specification

Input

The input will be n lines of space-separated numbers. (If you would like, you may also take a single comma-separated list of space-separated numbers, if that makes your code shorter.) For example:

10 20 30 40 50
15 25 35 45 55
20 30 40 50 60

Or:

10 20 30 40 50,15 25 35 45 55,20 30 40 50 60

Each list of numbers represents a list of users' reputation values on a single day.

Output

The output will be the same amount of n lines (or a comma-separated list of the same length). Each line / list item will be:

  • :D if there was a user whose reputation just became >= 10,000.
    • Multiple space-separated :Ds if there were multiple users who met or passed the 10,000 rep count. For example, :D :D :D for 3 new 10k users.
  • :( and then halt further output if the input is ambiguous or impossible (more on this in the next section).
  • nothing if neither of these conditions is true.

Ambiguity

It is possible that the input is ambiguous. For the purposes of this challenge, we assume that:

  • The reputation cap is 200 per day, ignoring accepts and bounties and the like for the sake of the challenge.
  • Users may not lose reputation (again for simplicity and for the challenge).

Input is considered ambiguous when it is impossible to determine which reputation values correspond to which user. For example, in the input 10 20,30 40, you can't tell whether the 10-rep user became the 30-rep user or the 40-rep user.

Input is considered impossible when the users from one day could not possibly have become the users from the next day. For example, in the input 10 20,310 320, this situation is clearly impossible because the users could not have gained 300 reputation in a day. Users losing reputation is also impossible.

Edge cases

  • The initial reputation values can start at anything (i.e. a user can start with 1337 reputation).
  • There is no output for the first line / list item.
  • The input will always be syntactically valid, meaning that the reputation values will always be positive integers, there will always be the same amount of reputation values per line / list item, etc.
  • The reputation values are not sorted; they may be in any order.

Test cases

Input: 9900,10000
Output: :D

Input: 9900 9950 9910,10100 9950 9910,10300 10150 10110
Output: :D,:D :D

Input: 10 20 30,42 10 20,10 242 20,442 42 10,0 0 0,442 42 10
Output: ,,,:(

Input: 10 20,15 25,15 25
Output: ,,

Input: 9999 9998 9997,10000 9998 9997,10000 10000 9997,10300 10000 10000
Output: :D,:D,:(

Input: 100,90,80,70
Output: :(

Input: 10000 10000 10000 9999,10000 10000 10000 10000,10010 10020 10030 10040
Output: :D,:(

Input: 9999 9998 9997 9996,10196 10197 10198 10199,10399 10199 10197 10196
Output: :D :D :D :D,

\$\endgroup\$
11
  • \$\begingroup\$ @MartinBüttner Ah, didn't notice that. Fixed \$\endgroup\$
    – Doorknob
    Commented Aug 7, 2014 at 13:11
  • \$\begingroup\$ The first step in that example is also ambiguous. \$\endgroup\$ Commented Aug 7, 2014 at 13:28
  • 1
    \$\begingroup\$ Whereas example 4 is not ambiguous. \$\endgroup\$ Commented Aug 7, 2014 at 13:29
  • \$\begingroup\$ (i.e. a user can start with 1337 reputation). I liked this coz that was my rep... wel 5 min ago until someone upvoted one of my answers xD \$\endgroup\$
    – Teun Pronk
    Commented Aug 7, 2014 at 13:29
  • \$\begingroup\$ Example 5, step 2 is also ambiguous (which 10k user is which?). Same goes for example 7 (unless you add some rule that discerning equal-rep users is irrelevant, but then how do you know which user was which on day one, if he tied with someone else later on?) \$\endgroup\$ Commented Aug 7, 2014 at 13:31

2 Answers 2

12
\$\begingroup\$

Ruby, 209 bytes

Edit: I switched to Ruby which shortened this by about 30%. See the edit history for the original Mathematica version. I suppose the main savings come from Ruby's permutation not ignoring switched positions of identical elements (which I had to trick Mathematica into).

This uses the newline-separated format.

gets.split('
').map{|s|s.split.map &:to_i}.each_cons(2){|a,b|a.permutation.map{|q|q.zip(b).map{|x,y|y-x}}.reject{|d|d.any?{|x|x<0||x>200}}.size!=1?abort(':('):(puts':D '*(a.count{|d|d<1e4}-b.count{|d|d<1e4}))}

The gist is this:

  • Get all consecutive pairs of days.
  • Get all permutations of the former day, and subtract each of these from the current day.
  • Ditch all results which contain differences that are negative or greater 200.
  • If the number of remaining permutations isn't 1, output :(.
  • Otherwise, output as many :D as there are new 10k users.
  • At the end, drop all days after the first :(.

Less golf:

gets.split("\n").map{|s|
  s.split.map &:to_i
}.each_cons(2){|a,b|
  a.permutation.map{|q|
    q.zip(b).map{|x,y|
      y-x
    }
  }.reject{|d|
    d.any?{|x|
      x<0||x>200
    }
  }.size!=1 ? abort(':(') : (puts ':D '*(a.count{|d|d<1e4}-b.count{|d|d<1e4}))
}

I think that's one beautiful chain of enumerators. :)

PS: Is it weird that I was the first one to submit an answer to this?

\$\endgroup\$
4
  • 9
    \$\begingroup\$ I don't think it's weird. Something tells me you have the home field advantage ;) \$\endgroup\$ Commented Aug 7, 2014 at 14:07
  • \$\begingroup\$ So this will fail some of the examples in the question, right? \$\endgroup\$
    – Cruncher
    Commented Aug 7, 2014 at 16:52
  • \$\begingroup\$ @Cruncher It will fail those which I think are wrong according to the spec (as I have mentioned in the comments). If Doorknob decides to change the spec instead of fixing the examples, I guess I'll have to rework this. \$\endgroup\$ Commented Aug 7, 2014 at 17:36
  • \$\begingroup\$ @MartinBüttner That's what I figured. Just confirming :) \$\endgroup\$
    – Cruncher
    Commented Aug 7, 2014 at 17:37
6
\$\begingroup\$

Haskell, 254 249 244 232 228

import Data.List
t=m(9999<)
p(a:b:r)=(a,b,r)%(filter(all(`elem`[0..200]))$nub$m(zipWith(-)b)$permutations a)
p _=""
(a,b,r)%(_:[])=(concat$m(const":D ")$t b\\t a)++'\n':p(b:r)
_%_=":("
m=map
main=interact$p.m(m read.words).lines

A little explanation: The algorithm is very similar to that used by MartinBüttner, except the nub that I spent some thought on. Note that a list difference is used for working out how many more reputation values are 10000 or larger on day n+1 compared to day n: t b\\t a.

I also agree with MartinBüttner on the interpretation of the specs and that some of the examples above are wrong, even to the point that example #2 is wrong (should be :().

\$\endgroup\$
6
  • \$\begingroup\$ Shouldn't you alias map? \$\endgroup\$ Commented Aug 22, 2014 at 16:02
  • 1
    \$\begingroup\$ That's right (saving 2 bytes), but another 10 bytes can be saved by making z infix and replacing replicate (length l) x with map (const x) l. Isn't Haskell fantastic? \$\endgroup\$ Commented Aug 23, 2014 at 23:04
  • \$\begingroup\$ it sure is. Nice golfing! On that note, Because function application has the highest precedence, you should be able to shorten (t b)\\(t a) to t b\\t a, golfing out 4 more bytes. \$\endgroup\$ Commented Aug 23, 2014 at 23:17
  • \$\begingroup\$ It would be nice if there was some code to find these places where code can be shortened automatically... Seems a bit big of a project though. \$\endgroup\$ Commented Aug 23, 2014 at 23:19
  • \$\begingroup\$ You're right @proudhaskeller, those paretheses were unncessary. Thanks. \$\endgroup\$ Commented Aug 23, 2014 at 23:29

Your Answer

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

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