It's Sunday, time for a round of code golf!

Challenge

Write the shortest source code by character count to determine if an input number is a "happy prime", "sad prime", "happy non-prime", or "sad non-prime."

Input

The input should be a integer that comes from a command line argument or stdin. Don't worry about handling big numbers, but do so if you can/want. Behavior would be undefined for input values less than 1, but 1 has a definite result.

Output

Output should print the type of number: "happy prime", "sad prime", "happy non-prime", or "sad non-prime." The trailing newline is optional.

Examples

$ happyprime 139
happy prime
$ happyprime 2
sad prime
$ happyprime 440
happy non-prime
$ happyprime 78
sad non-prime

Definitions

Just in case your brain needs a refresher.

Happy Number

From Wikipedia,

A happy number is defined by the following process. Starting with any positive integer, replace the number by the sum of the squares of its digits, and repeat the process until the number equals 1 (where it will stay), or it loops endlessly in a cycle which does not include 1. Those numbers for which this process ends in 1 are happy numbers, while those that do not end in 1 are unhappy numbers (or sad numbers).

For example,

  • 139
  • 1^2 + 3^2 + 9^2 = 91
  • 9^2 + 1^2 = 82
  • 8^2 + 2^2 = 68
  • 6^2 + 8^2 = 100
  • 1^2 + 0^2 + 0^2 = 1

Prime Number

A prime number is an integer greater than 1 and has precisely two divisors: 1 and itself.

Happy Prime

A happy prime, is therefore a number that is both happy and prime.

Answer Selection

Obviously the answer will be the shortest source code by character count that outputs the specified results in all cases that I test. I will mark the answer once the next (community decided) code golf challenge comes along, so we can focus all our energies on that one. :)

Decision

Well, it looks like the there is a new code golf in town and it has been about a week since this question was posted, so I've marked the shortest source code as the answer (gnibbler's 64 character Golfscript solution). That said, I enjoyed both the 99 character Mathematica solution by belisarius and the cryptic 107 character dc solution by Nabb.

To all others, great work! I've never had so many programming language environments on my computer. I hope everyone has learned some new, dirty tricks for their favorite language.

Reuse

I've re-published some of the code produced by this competition as an example for a script I wrote to test various programs against a reference implementation for auto-grading. The README in that directory explains where the source code comes from and states that all code is re-used under the CC BY-SA 2.5 license (as stated in SO's legal section). Each directory is labeled with your display name at the time of the submission.

If you have a problem with your code being re-used in this fashion or the attribution, let me know and I will correct the error.


dc - 98 chars

$ cat happyprimes
[happy][sad]?dsI[[I~d*rd0<H+]dsHxd4<h]dshx[r]sr1=rP[ ][ non-]_1lI[1-d2>rdlIr%0<p]dspx-2=rP[prime]p
$ echo 1  |dc happyprimes
happy non-prime
$ echo 139|dc happyprimes
happy prime
$ echo 2  |dc happyprimes
sad prime
$ echo 440|dc happyprimes
happy non-prime
$ echo 78 |dc happyprimes
sad non-prime

Mathematica 115 108 107 102 100 99 91 87 Chars


87 characters

Print[If[Nest[Tr[IntegerDigits@#^2]&,#,9]>1,Sad,Happy],If[PrimeQ@#," "," non-"],prime]&

-- Mr.Wizard


Da monkey learnt a few tricks (91 chars)

 Print[
       If[Nest[Plus@@(IntegerDigits@ #^2) &, #, 9] > 1, Sad, Happy ],
       If[PrimeQ@#, " ", " non-"], prime
      ] &

Invoke with %[7]

Edit 5 - 99 Chars/

Nine iterations is enough. Thanks @Nabb, @mjschultz

h = Print[
    If[Nest[Plus @@ (IntegerDigits@#^2) &, #, 9] > 1, "Sad ", "Happy "]
   , If[PrimeQ@#, "", "non-"], "prime"] &

Edit 4 - 100 Chars/

Same as Edit 3, replacing 10^2 by 99 (allowing 84 digits for input values) ... Thanks, @Greg

h = Print[
    If[Nest[Plus @@ (IntegerDigits@#^2) &, #, 99] > 1, "Sad ", "Happy "]
   , If[PrimeQ@#, "", "non-"], "prime"] &

Edit 3 - 102 Chars/

Reworked the loop again.

It is interesting that the recursion depth until eventually reaching 1 is bounded by (15 + Number of digits of the argument). See here

So for numbers with less than 85 digits (I think this limit is pretty well into the OP's "Don't worry about handling big numbers" consideration) the following code works

h = Print[
    If[Nest[Plus @@ (IntegerDigits@#^2) &, #, 10^2] > 1, "Sad ", "Happy "]
   , If[PrimeQ@#, "", "non-"], "prime"] &

I changed the "NestWhile" for the shorter "Nest", and so, instead of specifying a stop condition for the recursion, is enough to hardcode the desired recursion depth (10^2).

It is not very efficient, but that's the golfer's life :D

Edit 2 - 107 Chars/

Reworked the Sad/Happy assignment

h = Print[
     If[NestWhile[Plus @@ (IntegerDigits@#^2) &, #, # > 4 &] > 1,"Sad ","Happy "]
    ,If[PrimeQ@#, "", "non-"]
    , "prime"] &

All spaces/newlines except on literals are optional and added for readability

Explanation:

The

    NestWhile[Plus @@ (IntegerDigits@#^2) &, #, # > 4 &]

Recurses applying "function" [Add up sum of digits squared] until the result is 4 or less. The function has the property that it stagnates at "1", or enters the cycle {4, 16, 37, 58, 89, 145, 42, 20, 4, ...}.

So, when the outcome is "1", the number is "Happy" and when the outcome is "4", it is "Sad".

If the result is "2", the number is also SAD, because it'll enter the SAD cycle in the next iteration (2^2 = 4).

If the result is 3, the cycle is 3->9->81->65->61->37->58->89->145-> .... (Enters the SAD loop).

So, we can stop the recursion when the result is 4 or less, knowing that only a result of "1" will lead to a Happy number.

Perhaps other solutions may take advantage of this fact.

In fact, the results 5 and 6 also lead to SAD numbers, but that gives us only an efficiency boost and not a golfing advantage (I guess).

Edit 1 - 108 Chars/

Reworked the Loop Control logic

    h = Print[
        NestWhile[Plus@@(IntegerDigits@#^2) &, #, #>4 &] /.{1 →"Happy ",_→"Sad "}
          , If[PrimeQ@#, "", "non-"]
          , "prime"] &

Original - 115 Chars/

h = Print[
    If[NestWhile[Plus @@ (IntegerDigits@#^2) &, #, Unequal, All] == 1
        ,"Happy ", "Sad "],      
    If[PrimeQ@#, "", "non-"], "prime"] &

The statement

NestWhile[Plus @@ (IntegerDigits@#^2) &, #, Unequal, All]

performs the recursive application of the sums of the digits squared, until some value repeats. The "Unequal,All" part takes care of the comparison across the preceding values list. Finally returns the repeated value, which is "1" for Happy Numbers.

Sample run

h[7]
Happy prime
h[2535301200456458802993406410753]
Sad non-prime

Looping (Slightly changing the Print statement)

1 Happy non-prime
2 Sad prime
3 Sad prime
4 Sad non-prime
5 Sad prime
6 Sad non-prime
7 Happy prime
8 Sad non-prime
9 Sad non-prime
10 Happy non-prime
11 Sad prime
12 Sad non-prime
13 Happy prime

GolfScript - 64 chars (works for 1)

~:@.{0\`{15&.*+}/}*1=!"happy sad "6/=@,{@\)%!},,2=4*"non-prime">

This program does n iterations to determine the happiness of the number, which is very wasteful for large numbers, but code-golf is not about conserving resources other than characters. The prime test is similarly inefficient - dividing n by all the values from 1 to n inclusive and checking that there are exactly two values with zero remainder. So while it is theoretically correct, running with really large numbers is not practical on real computers

GolfScript - 63 chars (fails for 1)

~:@9{0\`{15&.*+}/}*1=!"happy sad "6/=@,2>{@\%!},!4*"non-prime">

Python - 127 chars

Beating both perl answers at this moment!

l=n=input()
while l>4:l=sum(int(i)**2for i in`l`)
print['sad','happy'][l<2],'non-prime'[4*all(n%i for i in range(2,n))*(n>1):]

I also ported this answer to GolfScript and it is just over 1/2 the size!