49

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.

Community
  • 1
  • 1
mjschultz
  • 1,776
  • 1
  • 17
  • 20
  • Can we assume the input number is greater than 1? Greater than some X? – Thomas Eding Aug 23 '10 at 03:27
  • Well, greater than or equal to 1. – mjschultz Aug 23 '10 at 03:36
  • 6
    Doctor Who Episode 184("42")? – nuclearsandwich Aug 23 '10 at 05:01
  • 1
    nuclearsandwich: Indeed, that was the impetus for the question. – mjschultz Aug 23 '10 at 11:57
  • it's valid to do this on SO? Awesome... – Corey Ogburn Aug 23 '10 at 18:13
  • 3
    Corey Ogburn: According to [meta](http://meta.stackexchange.com/questions/24242/acceptable-level-of-code-golf-questions) they are. Though some people don't like them, I think it provides an interesting view of various language features, and I've seen many unexpected ways of finding the answer here. (All shorter than my reference implementation.) – mjschultz Aug 23 '10 at 18:59
  • @mjschultz I think the message warning in SO needs you to prepend an "@" sign before the name to work. As in @Corey . This comment will commit suicide in 3 .. 2 .. 1 – Dr. belisarius Aug 23 '10 at 19:16
  • @belisarius: that is [correct](http://meta.stackexchange.com/questions/43019/how-do-comment-replies-work), I just assumed it was leftover from too many people using twitter. – mjschultz Aug 23 '10 at 19:33
  • 2
    Made a web application out of it in case you're in dire need to find out whether your favourite number is happy, prime, or both! http://startwithabreak.com/happyprimeweb/ Will try and golf it but seems like it's a bit late in the game. – Radu Aug 24 '10 at 16:11
  • @Radu: It's never too late! :-) – ShreevatsaR Aug 25 '10 at 02:08
  • It's good to see a lot of people using the regex-prime test. Although I suspect that may not work with 85-digit numbers – Adrian Pronk Aug 28 '10 at 02:15

33 Answers33

67

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
Nabb
  • 3,374
  • 3
  • 19
  • 32
  • 2
    About `dc`: [Wikipedia](http://en.wikipedia.org/wiki/Dc_%28computer_program%29), [manpage](http://linux.die.net/man/1/dc). – ShreevatsaR Aug 25 '10 at 01:20
  • Code golfing is the third use for dc, the other two are doing modular exponentiation and implementing bc on top of dc (and using bc instead of dc ;P ). – ninjalj Aug 25 '10 at 17:30
29

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
Mr.Wizard
  • 23,689
  • 5
  • 41
  • 116
Dr. belisarius
  • 59,172
  • 13
  • 109
  • 187
  • Oi, you're going to make me install Mathematica just so I can verify this! (Though I am fully convinced it is correct.) – mjschultz Aug 23 '10 at 15:02
  • 1
    Why do you use `10^2` instead of `100` or `99`, both of which are shorter? – Greg Aug 23 '10 at 15:35
  • @Greg yep, tnx ... I started using 10^99 for allowing greater input values and forgot to change that when came down to 85 digits ... Anyway the stack crashed with very big numbers :( – Dr. belisarius Aug 23 '10 at 15:44
  • belisarius: I'd bump it all the way down to `9` which puts you at 99 characters total. It still managed to evaluate `2535301200456458802993406410753` in no time on my system. – mjschultz Aug 23 '10 at 15:54
  • 1
    @mjschultz The required depth is not a monotone function. For example, calculating h[30] requires 11 iterations. The max depth value for numbers under 1000 is 15. So, 9 is way toooo low. – Dr. belisarius Aug 23 '10 at 16:00
  • 1
    @mjschultz Here is the compiled version for running in the free Mathematica Player, and the instructions. Just in case. http://code.google.com/p/magicnumbers/wiki/PageName?ts=1282589638&updated=PageName – Dr. belisarius Aug 23 '10 at 18:56
  • 1
    belisarius: Thanks for doing that, but as a student I have access to Mathematica. However, I'm sure others do not, so it's still useful! – mjschultz Aug 23 '10 at 19:08
  • `9` iterations should be sufficient up to `10^974` digits. – Nabb Aug 23 '10 at 19:41
  • @Nabb I guess you've a proof there :). I just followed a few experiments and the Wikipedia statement. Without a proof I didn't want to assume that, and reaching the SAD cycle may take as much as 16 iterations for very small numbers (15999, for example) – Dr. belisarius Aug 23 '10 at 20:10
  • 2
    @belisarius Your test condition is `>1`, i.e. happy numbers will have reached 1, not unhappy numbers some arbitrary value. The smallest values for n steps: s(5) = 7, s(6) = 356, s(7) = 78999. log₁₀(s(8)) ~ 975 (=78999/81). log₁₀(log₁₀(s(9))) ~ 974. log₁₀(log₁₀(log₁₀(s(10)))) ~ 974. 9 iterations is therefore sufficient for everything up to `10^10^10^974`, or `10^10^974` digits. I suppose I missed a step earlier. – Nabb Aug 23 '10 at 20:18
  • @Nabb Yep. Found the reference: http://www.research.att.com/~njas/sequences/index.html?q=7%2C356%2C78999&language=english&go=Search .. Thanks a lot – Dr. belisarius Aug 23 '10 at 20:24
19

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">
John La Rooy
  • 263,347
  • 47
  • 334
  • 476
  • I get...odd behavior when the input is `1`. Is that from a limitation of golfscript or something else? (It says `../lib/golfscript.rb:353:in `select': private method `select' called for nil:NilClass (NoMethodError)`.) – mjschultz Aug 24 '10 at 14:03
  • @mjschultz, darn - `1` is a special case in that solution. One char extra for a better primality test – John La Rooy Aug 25 '10 at 00:26
  • Well, let's run it on unreal computers then. – jave.web Sep 13 '14 at 10:22
13

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!

Community
  • 1
  • 1
John La Rooy
  • 263,347
  • 47
  • 334
  • 476
12

C#, 380 378 374 372 364 363 315 280 275 274 Chars

By replacing the recursive function with nested loops, I was able to bring the stroke count to a respectable 280 (100 less than the original).

class P{static void Main(string[]a){var s=new System.Collections.Generic.HashSet<int>();int n=int.Parse(a[0]),p=n>1?4:0,c,d=1;for(;++d<n;)if(n%d<1)p=0;for(;n>1&s.Add(n);n=c)for(c=0;n>0;c+=d*d,n/=10)d=n%10;System.Console.Write((n>1?"sad":"happy")+" non-prime".Remove(1,p));}}

Here it is with whitespace:

class P
{
    static void Main(string[] a)
    {
        var s = new System.Collections.Generic.HashSet<int>();
        int n = int.Parse(a[0]),
            p = n > 1 ? 4 : 0,
            c,
            d = 1;
        // find out if the number is prime
        while (++d < n)
            if (n % d < 1)
                p = 0;
        // figure out happiness
        for (; n > 1 & s.Add(n); n = c)
            for (c = 0; n > 0; c += d * d, n /= 10)
                d = n % 10;

        System.Console.Write(
            (n > 1 ? "sad" : "happy")
            + " non-prime".Remove(1,p)
            );
    }
}
Nick Larsen
  • 17,643
  • 6
  • 62
  • 94
ollb
  • 1,423
  • 1
  • 11
  • 16
9

C, 188 187 185 184 180 172 171 165

h(c,C,r,p){for(;C>1&&C%++p;);for(;c;c/=10)r+=c%10*(c%10);r&~5?h(r,C,0,1):printf(
"%s %sprime",r-1?"sad":"happy",p>=C&C>1?"":"non-");}main(c){h(c,c,0,scanf("%d",&c));}

$ ./a.out
139
happy prime

$ ./a.out
2
sad prime

$ ./a.out
440
happy non-prime

$ ./a.out
78
sad non-prime

This is one recursive function that never issues a return but either calls itself or prints output when it's done. The recursive function sums squared digits and determines prime-ness in two for loops. The scanf returns 1 which is put as an argument to h(), saving one ; and one 1 (and at the cost of having to use prefix ++p instead of postfix p++ which would make p>C possible instead of p>=C)

r&~5 is 0 for 1 4 5, of which 1 indicates happiness and the others sadness.

Next attempt: drop h() and make main() recursive.

mvds
  • 43,261
  • 8
  • 96
  • 109
  • Hmmm, the golfed version seems to give me nothing but segfaults on two machines, the non-golf version works except 1 gives a floating point exception. Ideas? (compiled with `gcc -o hp happyprime.c`) – mjschultz Aug 23 '10 at 01:41
  • Golfed version does not compile at all for me (clang 1.0). It tells me that the second argument to main must be `char**`. – dreamlax Aug 23 '10 at 02:04
  • fixed. Although with people specifying language versions (or custom golfing-languages) I would rather keep it at 178 and just specify platform and compiler: 32 bit linux using gcc. – mvds Aug 23 '10 at 09:47
  • As long as I know that it requires a 32-bit compiler that is fine, are there any other `gcc` args I need? I still get an exception with the `1` case from the prime detection routine (initial call is `p(1,0)` leading to a modulo operation with 0 in the divisor). – mjschultz Aug 23 '10 at 13:01
  • No other args that I use (although if possible I would opt for a lot of `-D.=...` args). I'll have a look if I can blend in the non-primeness of 1. – mvds Aug 23 '10 at 14:23
9

Python 2.6: 194 180 chars, 4 lines

import re
s=lambda n,l:0if n==1 else n in l or s(sum(int(a)**2for a in str(n)),l+[n])
n=input()
print['happy','sad'][s(n,[])],'non-'*bool(re.match(r'1?$|(11+?)\1+$','1'*n))+'prime'

The lexer being able to split 0if and 2for into two tokens each was a nice surprise to me :) (it doesn't work with else though)

Function s (sad) is recursive, and receives the list of previous numbers in the cycle as its second parameter. Primality is tested inline using the regexp trick.

By using the deprecated `n` syntax instead of str(n), one can further reduce the character count by 4 characters, but I choose not to use it.

Community
  • 1
  • 1
Roberto Bonvallet
  • 27,307
  • 5
  • 37
  • 57
8

Perl, 140 chars

sub h{$_==1&& happy||$s{$_}++&& sad
||do{$m=0;$m+=$_**2for split//;$_=$m;&h}}$n=$_=pop;
die h,$",(1x$n)=~/^1?$|^(11+?)\1+$/&&"non-","prime\n"

Linebreaks are optional.

hobbs
  • 187,508
  • 16
  • 182
  • 271
  • Ah, perl my first language. Interesting use of `die` for output, made me fix up my checker script. – mjschultz Aug 23 '10 at 01:47
  • Sorry, can be changed if necessary, but it's common practice here if nobody says "absolutely must go to stdout" :) – hobbs Aug 23 '10 at 01:58
  • if you have perl 5.10+, you can also -E and say. also, you can drop \n and just use newline. – muhmuhten Aug 24 '10 at 17:24
7

MATLAB 7.8.0 (R2009a) - 120 characters

Whitespace, newlines, and comments added for readability

n=input('');
s=n;
c={'happy ','sad ','non-'};
while s>6,
  s=int2str(s)-48;
  s=s*s';                    %'# Comment to fix code highlighting
end;
disp([c{[s<2 s>1 ~isprime(n)]} 'prime'])
gnovice
  • 123,396
  • 14
  • 248
  • 352
  • I'm curious about the last line ("disp") ... Could you explain it, please? – Dr. belisarius Aug 23 '10 at 19:36
  • @belisarius: `c` is a cell array of strings, and its contents are being indexed by a 1-by-3 logical array with elements `s<2`, `s>1`, and `~isprime(n)`. For every true entry in the index array, the contents of the corresponding cell are dumped into a set of square brackets, which concatenates them into one string along with the word `'prime'`. It is then displayed using `disp`. – gnovice Aug 23 '10 at 19:43
  • 1
    Any reason for the `while s>9,` line? It seems to cause invalid output when the input is `7`. Would `while s>6,` work? – mjschultz Aug 23 '10 at 19:53
  • @mjschultz @gnovice That's why I asked. I thought that the "disp" line made the magic to fix that. Tnx for the explanation! – Dr. belisarius Aug 23 '10 at 20:41
5

Ruby 1.9

169 168 146 chars

 h={1=>'happy'};s=->x{y=0;(y+=(x%10)**2;x/=10)while x>0;h[y]||(h[y]='sad';s[y])}
 $><<s[n=$*[0].to_i]+" #{'non-'if '1'*n=~/^1?$|^(11+?)\1+$/}prime"

If we use p instead of $><<, the code is shortened by 2 characters

Usage:

$ ruby happyprime.rb 139 happy prime $ ruby happyprime.rb 2 sad prime


Non golfed:

hash = {1->'happy'}
is_happy = lambda do |number|
  #sum = number.scan(/\d/).reduce(0){|acum, digit| acum + digit.to_i ** 2 }
  sum=0; 
  while (number > 0)
      sum+= (number%10)**2
      number/=10
  end
  return hash[sum] if hash[sum] # If 1, or if cycled and hash contains the number already
  h[sum] = 'sad'
  return is_happy.call(sum)
end
number = ARGV[0].to_i
string = ""
string += is_happy.call(number) # either 'happy' or 'sad'
string += is_prime(number) ? " non-prime" : "prime"
puts string

Where the is_prime method is left as an exercise to the reader ;)

AShelly
  • 32,752
  • 12
  • 84
  • 142
Chubas
  • 17,014
  • 4
  • 46
  • 48
  • 3
    Nice use of regular expressions as primality check! – Gabe Aug 23 '10 at 00:37
  • 1
    You can save 1 character by getting rid of the () for that if statement (leaving a single space behind) as * is already higher precedence than =~. – shanna Aug 23 '10 at 07:51
5

Haskell 172

h s n|n`notElem`s=h(n:s)$sum[read[k]^2|k<-show n]|1`elem`s="happy "|0<1="sad "
c n|n<2||any((0==).mod n)[2..n-1]="non-"|0<1=[]
y n=h[]n++c n++"prime"
main=readLn>>=putStr.y
Community
  • 1
  • 1
Thomas Eding
  • 31,027
  • 10
  • 64
  • 101
5

Javascript 244 250

function h(n){p=n=n<2?10:n;a=",";w="";s=[];while((y=a+s.join(a)+a).indexOf(a+n+a)<0){s.push(n);k=""+n;n=0;for(i=0;i<k.length;)c=k.charAt(i++),n+=c*c}w+=y.indexOf(",1,")<0?"sad ":"happy ";for(i=2;i<p;)p=p%i++?p:0;w+=p?"":"non-";return w+"prime"}

The above code should work in browsers without additional fancy functions and features (such as Array.prototype.indexOf and [] notation for strings), but I haven't tested it outside of Firefox.

Be aware that all but n are global variables (I'm just being cheap).

Usage

h(139) // returns "happy prime"
Community
  • 1
  • 1
Thomas Eding
  • 31,027
  • 10
  • 64
  • 101
  • 2
    Nice, I had to add a `}` at the end, but that is probably because I was using Firefox's Web Console. I'm impressed that Javascript and your code was able to handle `h(2535301200456458802993406410753)`! – mjschultz Aug 23 '10 at 13:07
  • Leaving the `}` out was a cut and paste mistake. Thanks. – Thomas Eding Aug 23 '10 at 17:28
4

Python 2.6

happy.py: 280 314 333 chars, 14 lines.

import re
def q(z):
 while z!=1:z=sum((int(a)**2 for a in `z`));yield z
def h(g):
 l=[]
 while 1:
  try:z=g.next()
  except:return 'happy '
  if z in l:return 'sad '
  l.append(z)
p=lambda n:not re.match(r'^1$|^(11+?)\1+$','1'*n)
n=int(input())
print h(q(n))+'non-prime'[4*p(n):]

Usage:

$ echo 139 | python happy.py
happy prime
$ echo 2 | python happy.py
sad prime
$ echo 440 | python happy.py
happy non-prime
$ echo 1234567 | python happy.py
sad non-prime

--

Readable version:

import re, sys

def happy_generator(z):
    while z != 1:
        z = sum((int(a)**2 for a in str(z)))
        yield z

def is_happy(number):
    last = []
    hg = happy_generator(number)
    while True:
        try:
            z = hg.next()
        except StopIteration:
            return True

        if z in last:
            return False
        last.append(z)

def is_prime(number):
    """Prime test using regular expressions :)"""
    return re.match(r'^1?$|^(11+?)\1+$', '1'*number) is None

n = int(sys.argv[1])

print "%s %sprime" % (('sad','happy')[is_happy(n)], ('non-','')[is_prime(n)])
Seth
  • 40,196
  • 9
  • 82
  • 118
4

Java: 294 286 285 282 277 262 260 chars


  • Update 1: replaced BigInteger#isProbablePrime() by regex. Saved 8 chars.

  • Update 2: replaced && by & (oops). Saved 1 char.

  • Update 3: refactored s a bit. Saved 3 chars.

  • Update 4: the test on n!=1 was superfluous. Saved 5 chars.

  • Update 5: replaced regex by for loop and refactored happy for loops little bits. Saved 15 chars.

  • Update 6: replaced int/Integer by long/Long. Saved 2 chars.


import java.util.*;class H{public static void main(String[]a){long n=new Long(a[0]),p=n>1?1:0,s,d=1;while(++d<n)if(n%d<1)p=0;for(Set c=new HashSet();c.add(n);n=s)for(s=0;n>0;s+=d*d,n/=10)d=n%10;System.out.printf("%s %sprime",n>1?"sad":"happy",p>0?"":"non-");}}

With newlines:

import java.util.*;
class H{
 public static void main(String[]a){
  long n=new Long(a[0]),p=n>1?1:0,s,d=1;
  while(++d<n)if(n%d<1)p=0;
  for(Set c=new HashSet();c.add(n);n=s)for(s=0;n>0;s+=d*d,n/=10)d=n%10;
  System.out.printf("%s %sprime",n>1?"sad":"happy",p>0?"":"non-");
 }
}
Community
  • 1
  • 1
BalusC
  • 992,635
  • 352
  • 3,478
  • 3,452
  • Shouldn't that be `new Char[p]`? Anyway, good job. You beat me – TheLQ Aug 23 '10 at 02:05
  • @BalusC, Character Count = 286. :-/ – st0le Aug 23 '10 at 13:40
  • @BalusC, I can save 3 chars. :) I can't seem to `Save my Edit` some proxy error on my side, so i'll post it as a comment. Please Check it and if it's any good update the answer. – st0le Aug 23 '10 at 13:50
  • import java.util.*;class H{public static void main(String[]a){int n=new Integer(a[0]),p=n,s,d;Set c=new HashSet();for(;n!=1&c.add(n);n=s)for(s=0;n>0;d=n%10,s+=d*d,n/=10);System.out.printf("%s %sprime",n==1?"happy":"sad",new String(new char[p]).matches(".?|(..+?)\\1+")?"non-":"");}} – st0le Aug 23 '10 at 13:51
  • @st0le: the trailing newline shouldn't count. It's really 285. As per your suggestion, yes that's better. – BalusC Aug 23 '10 at 13:54
  • @BalusC, 1 more byte. Move the `Set c=new HashSet()` into the first part of the `for(;c.add(n);)` loop. that saves a semicolon. :) `for(Set c=new HashSet();c.add(n);n=s)` – st0le Aug 24 '10 at 06:00
  • @BalusC,Haha, Ok, 7 bytes more. Instead of `new String(new char[p])` use `(""+new char[p])`. :D – st0le Aug 24 '10 at 06:06
  • @st0le: I saved after all 15 chars. Thanks you for the hints :) – BalusC Aug 24 '10 at 12:50
  • @BalusC, I'm not done yet, `if(n%d<1)p=0` change it to `p*=(n%d)`...;) or `&=` (same thing) – st0le Aug 24 '10 at 14:10
  • @st0le: 2 more chars off, those parentheses are superfluous. Regardless, that gives a false negative for `139`. – BalusC Aug 24 '10 at 14:28
  • also `p=n>1?1:0` can be changed to `p=n`, i think. Since `Behavior would be undefined for input values less than 1` So it ought to do. :D – st0le Aug 25 '10 at 05:07
  • @st0le: 1 is valid input. It should become 0 for the case that `while` loop doesn't enter (so that `p>0` in the print is still valid for 1). Changing int to long is a good one, thought of it as well in previous stages, but it didn't work well with new char[n] when the regex was still there, so I didn't use it. – BalusC Aug 25 '10 at 17:38
4

J: 113 characters

h=.1=$:@([:+/[:*:@"."0":)`]@.(e.&1 4)
1!:2&2;(({&('sad ';'happy '))@h,({&('non-prime';'prime'))@(1&p:))".(1!:1]3)

 

$ echo -n 7 | jc happy.ijs
happy prime
$ echo -n 139 | jc happy.ijs
happy prime
$ echo -n 2 | jc happy.ijs
sad prime
$ echo -n 440 | jc happy.ijs
happy non-prime
$ echo -n 78 | jc happy.ijs
sad non-prime
Community
  • 1
  • 1
cobbal
  • 66,343
  • 18
  • 135
  • 154
3

Perl, 135C

sub h{my$s;$s+=$_**2for split//,pop;($s-4)?($s-1)?&h($s):1:0}$a=pop;
print h($a)?happy:sad,$",(1x$a)=~/^1?$|^(11+?)\1+$/&&"non-",prime

Combined C and Perl

Community
  • 1
  • 1
3

C++, 258 231 230 227 chars

#include<iostream>
#define w while
int m,n,i,j,t=10;int main(){w(std::cin>>n){j=0,m=n;w(n>1){i=0;do i+=n%t*(n%t);w(n/=t);n=n*n+i;n=++j&0xFFFF?n:0;}i=1;w(m%++i&&j>1);std::cout<<(n?"happy":"sad")<<(i-m?" non-":" ")<<"prime\n";}}

not the best golfing language, gave it a good shot anyway. Most of this is straight C so would probably be shorter in C as well.

EDIT

Generally tidied it up, think it's pretty much at the limit now without a complete rerwrite.

Also forgot to add that this assumes that there are no numbers with a sequence with over 0xFFFF numbers which a pretty sensible assumption.

EDIT 2

fixed a bug. rearranged to remove the excessive calls to std::cout.

Scott Logan
  • 1,438
  • 2
  • 15
  • 33
  • A few C golfing tricks which should shave off some: You could try to use the ternary conditional `cond?true:false` which also has useful low precedence properties, comparison for (non-)equality is best done using `a-b` rather than `a!=b`, and looping is shorter with `for` - although `while()` takes as much room as `for(;;)`, the latter gives space to put statements in without the cost of an extra `;`. And there are a few more chars to win still. – mvds Aug 23 '10 at 09:56
  • I know this will cost you a few character, but I get stuck in the last `while` loop when the input is `1`. – mjschultz Aug 23 '10 at 13:48
  • @mjschultz: thanks fixed it now. thanks for doing my debugging for me as well. ;) – Scott Logan Aug 23 '10 at 14:52
3

VBA 245 characters

Good starter, will trim if time allows. Its only my 2nd go at code golf!

Public Sub G(N)
Dim Z, D, X, O
X = N
Z = N
Do Until Z = 1 Or X > N Or X = 0
    X = 0
    For D = 1 To Len(CStr(Z))
        X = X + CLng(Mid(CStr(Z), D, 1) ^ 2)
    Next D
    Z = X
Loop
If Z = 1 Then O = "Happy" Else O = "Sad"
D = 2
Do
    If N / D = Int(N / D) Then O = O & " Not Prime": Debug.Print O: Exit Sub
    D = D + 1
Loop While D < N
O = O & " Prime"
Debug.Print O
End Sub
Kevin Ross
  • 7,065
  • 2
  • 19
  • 25
3

MATLAB - 166 chars

function happyprime(a)
h={'non-prime','prime'};
h=h{isprime(str2num(a))+1};
for i=1:99
   a=num2str(sum(str2num((a)').^2));
end
s={'Sad ','Happy '};
[s{(str2num(a)==1)+1},h]

Usage

happyprime 139
ans =
Happy prime
Jonas
  • 73,844
  • 10
  • 134
  • 175
2

Clojure, 353 318 298 261 230 chars

(defn h[x m](cond(= x 1)"happy "(m x)"sad ":else(recur(reduce +(for[n(map #(-(int %)48)(str x))](* n n)))(assoc m x 1))))(println(let [x (read)](str(h x{})(if(re-matches #"^1$|^(11+)?\1+"(apply str(repeat x\1)))"non-""")"prime")))

ptimac:clojure pti$ clj  happy.clj 139
CP=/Users/pti/playpen/clojure:/Users/pti/Library/Clojure/lib/clojure.jar:/Users/pti/Library/Clojure/lib/jline.jar:/Users/pti/Library/Clojure/lib/clojure-contrib.jar
happy prime
ptimac:clojure pti$ clj  happy.clj 440
CP=/Users/pti/playpen/clojure:/Users/pti/Library/Clojure/lib/clojure.jar:/Users/pti/Library/Clojure/lib/jline.jar:/Users/pti/Library/Clojure/lib/clojure-contrib.jar
happy non-prime
ptimac:clojure pti$ clj  happy.clj 2
CP=/Users/pti/playpen/clojure:/Users/pti/Library/Clojure/lib/clojure.jar:/Users/pti/Library/Clojure/lib/jline.jar:/Users/pti/Library/Clojure/lib/clojure-contrib.jar
sad prime
ptimac:clojure pti$ clj  happy.clj 78
CP=/Users/pti/playpen/clojure:/Users/pti/Library/Clojure/lib/clojure.jar:/Users/pti/Library/Clojure/lib/jline.jar:/Users/pti/Library/Clojure/lib/clojure-contrib.jar
sad non-prime

I am leaning on the clojure contrib for the primes sequence. I wonder if using for loops would be shorter than recursion?

I read up on the regex prime number check. It's awesome and removes 30 chars and my dependency on clojure.contrib. I also refactored the command line parsing somwhat and inlined a function.

Pre golf(somewhat outdated):

(defn h[x m]
  (cond
   (= x 1) "happy "
   (m x) "sad "
   :else (recur
               (reduce +
                 (for [n (map #(- (int %) 48) (str x))] (* n n))) 
               (assoc m x 1))))

    (println
      (let [x (read)]
        (str
           (h x{})
           (if (re-matches #"^1$|^(11+)?\1+"(apply str(repeat x \1)))
             "non-"
             "")
           "prime")))
Peter Tillemans
  • 33,685
  • 9
  • 76
  • 112
  • Nice, I've never worked with clojure before, but I had to change the `(nth *command-line-args* 1)` to `(nth *command-line-args* 2)`. (1 being your script's name). – mjschultz Aug 23 '10 at 13:27
  • Yes that seems to have to do with the bash scripts and the change from the Script class to clojure.main for script support. – Peter Tillemans Aug 23 '10 at 20:22
2

F#, 249 chars

let n=stdin.ReadLine()|>int
let rec s x=seq{yield x;yield!string x|>Seq.sumBy(fun c->(int c-48)*(int c-48))|>s}
printfn"%s %sprime"(if s n|>Seq.take 99|>Seq.exists((=)1)then"happy"else"sad")(if[2..n/2]|>Seq.exists(fun d->n%d=0)then"non-"else"")
Brian
  • 113,581
  • 16
  • 227
  • 296
2

Scala, 253 247 246

object H{def main(a:Array[String]){var s=Set(0)
val n=a(0)toInt
def r(m:Int):String={val k=""+m map(c=>c*(c-96)+2304)sum;if(k<2)"happy"else if(s(k))"sad"else{s+=k;r(k)}}
printf("%s %sprime",r(n),if(n<2|(2 to n-1 exists(n%_==0)))"non-"else"")}}

Probably there is some room for improvements. The damn test for 1 as non-prime costs 6 chars :-(

Landei
  • 52,346
  • 12
  • 89
  • 188
2

PHP 217 Chars

$t=$argv[1];for($z=$t-1,$p=1;$z&&++$p<$t;)$z=$t%$p;$f=array(1);while(!in_array($t,$f,1)){$f[]=$t;$t=array_reduce(str_split($t),function($v,$c){return $v+=$c*$c;});}print($t<2?"happy ":"sad ").(!$z?"non-":"")."prime";

Usage:

$ php -r '$t=$argv[1];for($z=$t-1,$p=1;$z&&++$p<$t;)$z=$t%$p;$f=array(1);while(!in_array($t,$f,1)){$f[]=$t;$t=array_reduce(str_split($t),function($v,$c){return $v+=$c*$c;});}print($t<2?"happy ":"sad ").(!$z?"non-":"")."prime";' 139
happy prime
Kevin Vaughan
  • 12,450
  • 4
  • 25
  • 21
2

Javascript, 192 190 185 182 165 158 chars

The prime checking runs from 2 to square root of N. I wasted few chars there...

In one line:

for(x=2,y=m=n=prompt();x*x<y&&n%x++;);for(s={};!s[m];m=p)for(s[m]=1,p=0;m;m=(m-=k=m%10)/10,p+=k*k);alert((m-1?'sad':'happy')+(n-1&&x*x>y?' ':' non-')+'prime')

Formatted:

// Getting the number from the input and checking for primeness
// (ie. if after the loop x>y => n is prime)
for (x=2, y=m=n=prompt(); x*x<y && n%x++;)

// Checking for happiness
// the loop is broken out of if m is already encountered
// the m==1 after the loop indicates happy number
for(s={}; !s[m]; m=p)
    for (s[m]=1, p=0; m; m=(m -= k=m%10)/10, p+=k * k);

alert((m-1 ? 'sad' : 'happy') + (n-1 && x*x>y ? ' ' : ' non-') + 'prime')

Check: http://jsfiddle.net/TwxAW/6/

Marko Dumic
  • 9,530
  • 3
  • 27
  • 33
2

Perl, 113 109 105 chars

Beating all Python answers at this moment! SCNR.

$n=$s=<>;$s=0,s/\d/$s+=$&*$&/ge while($_=$s)>4;die$s>1?sad:happy,$","non-"x(1x$n)=~/^1$|(^11+)\1+$/,prime
ninjalj
  • 39,486
  • 8
  • 94
  • 141
1

Python 2.6, 300 298 294 chars

Different from previous answer in that this doesn't use regex.

I'm sure there's some way of shortening my h(x) function, but I'm still learning Python so I've got no idea.

p(x) returns True if it's a non-prime. h(x) returns True if it's happy. I've done the t = True so that it shortens the character count when doing the truth check.

x=input()
def p(x):
 if x==1 or 1 in [1 for i in range(2,x) if x%i==0]: return True
def h(x):
 l=[]
 while x not in l:
  l.append(x)
  x=sum([int(i)**2 for i in str(x)])
 if 1 in l: return True
if h(x):print'happy',
elif not h(x):print'sad',
if p(x):print'non-prime'
elif not p(x):print'prime'
avacariu
  • 2,360
  • 3
  • 20
  • 24
  • Close, you'll need to fix it for the `1` case (1 being non-prime). Also you can strip the `[]` in the `sum()`. You could also probably just do `if h(x):` and the like. – mjschultz Aug 23 '10 at 01:59
  • Can someone please test this for me. I'm getting a weird problem: if I run this as a .py file from CLI, it says that 1 is prime. If I write the exact same function in an interpreter, it says 1 is not prime... – avacariu Aug 23 '10 at 02:22
  • So I think I fixed the `1` case this time. I'm still confused a bit about the whole logic of it though :P – avacariu Aug 23 '10 at 02:31
1

Python (285 270 269 246 241 247 240 237 chars, 21 20 21 18 19 lines)

n=input()
s='prime'
for i in range(2,n):
    if n%i==0: 
        s='non'+s
        break
f=list(str(n))
g=set()
while n!=1:
    n=sum([int(z)**2 for z in f])
    if n in g:
        s='sad '+s
        break
    else:
        f=list(str(n))
        g.add(n)
else:
    s='happy '+s
print s

EDIT: Yes, the number went up, there was a bug :-P

Chinmay Kanchi
  • 54,755
  • 21
  • 79
  • 110
  • using `n=input()` will really cut down on your char count. And it seems to be accepted in the rules. And some things to fix: since you use a `for` loop it appends lots of `non`'s to the `s`. Also, `1` is not prime so you'd need to fix that. – avacariu Aug 23 '10 at 02:42
  • Yes, I realised that as soon as I posted. Edited now. – Chinmay Kanchi Aug 23 '10 at 02:43
  • You don't need the `int()`. `input()` already evaluates the input and makes it an int if it already is one. – avacariu Aug 23 '10 at 02:50
  • I fixed the loop problem and the unnecessary int(). You just have to fix the `1` case. – avacariu Aug 23 '10 at 02:58
  • Oh, I didn't know that. Also managed to cut down one more line by putting the if and statement inside a single line. Also, the lambda was unnecessary, so, one more line and a bunch of characters gone there... – Chinmay Kanchi Aug 23 '10 at 03:01
  • Did your changes get posted? I don't see them here. Oh, and the `int(n)` in your `for` loop is unnecessary because `n` is already an integer. **EDIT:** Nevermind; the changes are here now. – avacariu Aug 23 '10 at 03:05
  • Done :). I don't think it can be shortened any more now without serious mental effort. It's the shortest Python solution here by a long way. – Chinmay Kanchi Aug 23 '10 at 03:09
  • You need that `break` statement in your for loop or else you get this result for 440: `happy nonnonnonnonnonnonnonnonnonnonnonnonnonnonprime` – avacariu Aug 23 '10 at 03:13
  • Made it even shorter using `while: else:`. – Chinmay Kanchi Aug 23 '10 at 03:23
  • Change `range(2,n/2+1)` to `range(2,n-1)` to save some characters? Who cares about efficiency? Don't you need a `-` after `non`? – Thomas Eding Aug 23 '10 at 03:31
  • Actually, since `xrange(start, stop)` is non-inclusive of the last number, just `xrange(2,n)` will do :) – Chinmay Kanchi Aug 23 '10 at 03:43
  • 1
    Rather than `s='non'+s;break` you can use `s='non-prime'` and save a few chars. – Gabe Aug 23 '10 at 04:17
  • @Gabe: but he'd still need the `break` statement in there so it doesn't do the `nonononononononononononprime` problem. – avacariu Aug 23 '10 at 04:36
  • 1
    vlad003: The `break` was only necessary because he was concatenating with the previous value. Since `s='non-prime'` is idempotent, there's no need for the `break`. – Gabe Aug 23 '10 at 04:46
1

Python, 169 168 158 157 166 164 162 chars, 4 lines

l=n=input()
while l>4:l=sum(int(i)**2for i in str(l))
print['sad','happy'][l==1and str(n)!=1],
print['non-',''][n!=1 and sum(n%i==0for i in range(1,n))<2]+"prime"

Takes a number from stdin and doesn't muck around with regexes like the other python answer, although I must admit that is pretty cool. I could also shave off 6 chars by using backticks instead of the str-function, but let's play nice.

EDIT: Fixed a bug with 1 being a prime, which bumped up the charcount by 10. I figure there must be a more concise way than mine for doing this.

EDIT 2: Apparently, python 2.6 allows print[1, 2] without a space between the two.

EDIT 3: Used another calculation for the happy numbers

thepandaatemyface
  • 4,323
  • 6
  • 22
  • 30
  • I do appreciate the non-use of regex, but yours seems to detect `1` as prime and `7` as sad. (Also, strictly speaking the last comma should be a `+`.) – mjschultz Aug 23 '10 at 14:53
  • Hmmm, it still claims that `7` is a "sad prime", instead of "happy prime". Also, you could remove the space before both the `for`s as well. – mjschultz Aug 23 '10 at 15:57
1

Python - 142 chars

I was playing around with this idea, but it turned out too long. Perhaps someone can find a way to make it shorter. Maybe it'll turn out better in Ruby. Should be fun to understand how it works anyway :)

n=input();L=[n];print"%s non-prime"[4*([1for f in range(1,n)if L.append(sum(int(x)**2for x in`L[-1]`))or n%f<1]==[1]):]%['sad','happy'][1in L]
John La Rooy
  • 263,347
  • 47
  • 334
  • 476
1

GNU sed, 146 125 chars

Run with sed -rf file. Using -r saves 5 backslashes.

Needs bc, printf, and a shell with support for here-strings.

h
s/^/printf %*s /e
s/^ $|^(  +)\1+$/non-/
s/ *$/prime/
x
:a
s/./+&*&/g
s//bc<<</e
tb
:b
s/^1$/happy/
s/^4$/sad/
Ta
G
s/\n/ /

GNU sed, 155 141 chars (needs neither printf nor here-strings)

Uses the more standard traditional yes and head instead of printf.

h
:a
s/./+&*&/g
s/.*/echo 0&|bc/e
tb
:b
s/^1$/happy/
s/^4$/sad/
Ta
x
s/^/yes|head -/e
s/\n//g
s/^y$|^(yy+)\1+$/non-/
s/y*$/prime/
x
G
s/\n/ /

GNU sed, 134 115 chars (slightly bad formatted output)

Slightly shorter version, doesn't respect output formatting (has extra spaces and a newline between happy/sad and (non-)prime).

h
:a
s/./+&*&/g
s//bc<<</e
tb
:b
s/^1$/happy/
s/^4$/sad/
Ta
p
g
s/^/printf %*s /e
s/^ $|^(  +)\1+$/non-/
s/$/prime/
ninjalj
  • 39,486
  • 8
  • 94
  • 141
1

PARI/GP

184 bytes

A Bit late to participate, but here's a short one.

a(x,v=[])=s=0;while(x,s+=(x%10)^2;x\=10);for(k=1,length(v),if(v[k]==s,return("sad ")));return(if(s==1,"happy ",v=concat(v,s);a(s,v)));f(x)=print(a(x),if(!isprime(x),"non-",""),"prime")

To use it. Write f(139)

st0le
  • 32,587
  • 8
  • 83
  • 88
0

Racket, 286 characters

Only issue is that 1 is prime.

(define d
  (lambda (n)
    (cond
      ((= n 0) 0)
      ((+
       (expt (modulo n 10) 2)
       (d (floor (/ n 10)))
       ))
      )
    )
  )

(define dd
  (lambda (n l)
    (cond
      ((= n 1) "happy ")
      ((for/or ([v l]) (= n v)) "sad ")
      ((dd (d n) (cons n l)))
      )
    )
  )

(define cg
  (lambda (n)
    (display (dd n '()))
    (display
    (if
     (for/and
       ([i (in-range 2 (floor (+ (sqrt n) 1)))]) (> (modulo n i) 0))
       "prime" "non-prime"
     ))
    )
  )
Community
  • 1
  • 1
Turing
  • 786
  • 4
  • 17
0

JavaScript - 171 (Closure Compiler Compressed)

Just found this fun challenge. This is 171 characters in JavaScript:

function h(a){for(b=2,c="";b<a;b++)a%b||(c="non-");c+="prime";for(b={};;){if(a==1)return"happy "+c;if(b[a])return"sad "+c;b[a]=1;for(e=0;a;){d=a%10;e+=d*d;a=(a-d)/10}a=e}}

I ran the source code through the Closure Compiler in Advanced Mode to compress it. The source:

function h(num)
{
    // Check for prime-ness
    // Save the word "prime" by attaching a "non-" in front if it has a factor
    // Notice that we are not concerned with performance here, otherwise should
    // break when a factor is found and should only go up to Math.sqrt(num)

    for (var x=2, prime=""; x < num; x++) {
        if (!(num % x)) prime="non-";
    }

    // Create "prime" or "non-prime"

    prime += "prime";

    // Keep all visited numbers in a hash

    var visited = {};

    while(true) {
        // If the number is one, then happy
        if (num == 1) return "happy " + prime;

        // Otherwise put it into the hash
        if (visited[num]) return "sad " + prime;
        visited[num] = 1;

        // Recalculate the new number by shifting through each digit
        var sum = 0;
        while (num) {   // Stop when num -> 0 (i.e. no more digits)
            var digit = num % 10;
            sum += digit * digit;
            num = (num - digit)/10; // Shift by one digit
        }

        num = sum;
    }
}
Stephen Chung
  • 14,113
  • 1
  • 30
  • 47