Code Golf - π day
Asked Answered
T

26

95

The Challenge

Guidelines for code-golf on SO

The shortest code by character count to display a representation of a circle of radius R using the *character, followed by an approximation of π.

Input is a single number, R.

Since most computers seem to have almost 2:1 ratio you should only output lines where y is odd. This means that when R is odd you should print R-1 lines. There is a new testcase for R=13 to clarify.

eg.

Input
    5
Output      Correct                          Incorrect

        3    *******                    4      *******
        1   *********                   2     *********
       -1   *********                   0    ***********
       -3    *******                   -2     *********
           2.56                        -4      *******
                                            3.44

Edit: Due to widespread confusion caused by odd values of R, any solutions that pass the 4 test cases given below will be accepted

The approximation of π is given by dividing twice the number of * characters by .
The approximation should be correct to at least 6 significant digits.
Leading or trailing zeros are permitted, so for example any of 3, 3.000000, 003 is accepted for the inputs of 2 and 4.

Code count includes input/output (i.e., full program).

Test Cases

Input
    2
Output
     *** 
     *** 
    3.0

Input
    4
Output
      *****  
     ******* 
     ******* 
      *****  
    3.0

Input
    8
Output
         *******     
      *************  
     *************** 
     *************** 
     *************** 
     *************** 
      *************  
         *******     
    3.125

Input
    10
Output
          *********      
       ***************   
      *****************  
     ******************* 
     ******************* 
     ******************* 
     ******************* 
      *****************  
       ***************   
          *********      
    3.16

Bonus Test Case

Input
    13
Output

           *************       
        *******************    
       *********************   
      ***********************  
     ************************* 
     ************************* 
     ************************* 
     ************************* 
      ***********************  
       *********************   
        *******************    
           *************                                          
    2.98224852071
Talebearer answered 13/3, 2010 at 22:38 Comment(13)
You may wish to clarify whether the "input" is on the command line, or on stdin.Twinkle
@Greg Hewgill, Feel free to choose whichever is most convenient for the language you are using :)Talebearer
@Greg Hewgill, Some (that is, very few) programming language implementations do not have a notion of "command line".Stewardess
@LiraNuna, thanks. That means a lot coming from the king of code-golf questions :)Talebearer
You mentioned that output is allowed to have leading(03) or trailing zeros(3.0), what about for input?Sphingosine
@wallacoloo, To be fair, your answer should work with the input given in the testcases. If it also works with 08 and 8e0 and 8.00 that is ok too of course.Talebearer
I notice that few of the answers follow the rule of only putting out lines where y is odd. Given an odd value of r (not shown in the test cases), most will output lines where y is even!Ralina
@MtnViewMark, I've commented to the frontrunners and added an example to the questionTalebearer
I've edited my submission (104 char python) to demonstrate my questions about odd-numbered lines.Terrorism
I've decided to make the odd number test case optional as it raises too many issues and violates the "fun" principleTalebearer
Rule abuse challenge: Make code that is shorter than anyone else's code by only supporting the 4 required test cases.Buehler
@Brian, good luck with that :)Talebearer
wait, we can cheat? updated my answer with a third option :DTerrorism
S
15

In dc: 88 and 93 93 94 96 102 105 129 138 141 chars

Just in case, I am using OpenBSD and some supposedly non-portable extensions at this point.

93 chars. This is based on same formula as FORTRAN solution (slightly different results than test cases). Calculates X^2=R^2-Y^2 for every Y

[rdPr1-d0<p]sp1?dsMdd*sRd2%--
[dd*lRr-vddlMr-32rlpxRR42r2*lpxRRAP4*2+lN+sN2+dlM>y]
dsyx5klNlR/p

88 chars. Iterative solution. Matches test cases. For every X and Y checks if X^2+Y^2<=R^2

1?dsMdd*sRd2%--sY[0lM-[dd*lYd*+lRr(2*d5*32+PlN+sN1+dlM!<x]dsxxAPlY2+dsYlM>y]
dsyx5klNlR/p

To run dc pi.dc.

Here is an older annotated version:

# Routines to print '*' or ' '. If '*', increase the counter by 2
[lN2+sN42P]s1
[32P]s2
# do 1 row
# keeping I in the stack
[
 # X in the stack
 # Calculate X^2+Y^2 (leave a copy of X)
 dd*lYd*+ 
 #Calculate X^2+Y^2-R^2...
 lR-d
 # .. if <0, execute routine 1 (print '*')
 0>1
 # .. else execute routine 2 (print ' ')
 0!>2 
 # increment X..
 1+
 # and check if done with line (if not done, recurse)
 d lM!<x
]sx
# Routine to cycle for the columns
# Y is on the stack
[
  # push -X
  0lM- 

  # Do row
  lxx 
  # Print EOL
  10P
  # Increment Y and save it, leaving 2 copies
  lY 2+ dsY 
  # Check for stop condition
  lM >y
]sy
# main loop
# Push Input value
[Input:]n?
# Initialize registers
# M=rows
d sM
# Y=1-(M-(M%2))
dd2%-1r-sY
# R=M^2
d*sR
# N=0
0sN
[Output:]p
# Main routine
lyx
# Print value of PI, N/R
5klNlR/p
Scotism answered 13/3, 2010 at 22:38 Comment(4)
Doesn't work with linux dc, but I can confirm it works on openbsd. Awesome!Talebearer
@Carlos, yes the ( operator sure is handy. too bad it remains unimplemented in the dc that comes with linuxTalebearer
@Azriel - "A complete rewrite of the dc command using the bn(3) big number routines first appeared in OpenBSD 3.5." I didn't know that. Some nice new operators are included, but they are marked as "non-portable extensions".Feebleminded
Yeah, the ( operator alone allowed to shed 6 strokes!Scotism
F
119

C: 131 chars

(Based on the C++ solution by Joey)

main(i,j,c,n){for(scanf("%d",&n),c=0,i|=-n;i<n;puts(""),i+=2)for(j=-n;++j<n;putchar(i*i+j*j<n*n?c++,42:32));printf("%g",2.*c/n/n);}

(Change the i|=-n to i-=n to remove the support of odd number cases. This merely reduces char count to 130.)

As a circle:

      main(i,j,
   c,n){for(scanf(
  "%d",&n),c=0,i=1|
 -n;i<n;puts(""),i+=
 0x2)for(j=-n;++j<n;
 putchar(i*i+j*j<n*n
 ?c++,0x02a:0x020));
  printf("%g",2.*c/
   n/n);3.1415926;
      5358979;}
Facile answered 13/3, 2010 at 22:38 Comment(13)
I like how you added circles to the code to turn it into a circle. Would +000 be preferable?Hintz
congratulations, j*j++ is undefined behaviourHarleigh
@sellibitze: Ah right. The update should have removed the undefined behavior (and eliminated the odd-number bug.)Gabionade
There's an IOCCC entry very much along these lines. It approximates pi by counting its own characters, shaped in a circle.Stewardess
Can be down 2 chars if you turn <= into a > comparison.Starchy
wouldn't that only be one character...?Sphingosine
No because he compares with <= twice.Starchy
@Jasper: How? The i<=n must be like that due to the for loop, the i*i+j*j<=n*n must be like that otherwise the c++,42 expression needs parenthesis.Gabionade
You can just write n>i and n*n>i*i+j*j they mean the same thing.Starchy
How does main() take four int arguments?Aerodonetics
@Load: 5.1.2.2.1/1: The function called at program startup is named main. It shall be defined … or in some other implementation-defined manner. So that's because the implementation can accept this form.Gabionade
If there are no command line args, i=1 already, so you can say i|=-nTalebearer
@KennyTM: Using a non-standard main() renders the program non-portable. Is that what you intended?Aerodonetics
B
46

XSLT 1.0

Just for fun, here's an XSLT version. Not really code-golf material, but it solves the problem in a weird-functional-XSLT-kind of way :)

<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:msxsl="urn:schemas-microsoft-com:xslt" >
  <xsl:output method="html"/>

  <!-- Skip even lines -->
  <xsl:template match="s[@y mod 2=0]">
    <xsl:variable name="next">
      <!-- Just go to next line.-->
      <s R="{@R}" y="{@y+1}" x="{-@R}" area="{@area}"/>
    </xsl:variable>
    <xsl:apply-templates select="msxsl:node-set($next)"/>
  </xsl:template>

  <!-- End of the line?-->
  <xsl:template match="s[@x &gt; @R]">
    <xsl:variable name="next">
      <!-- Go to next line.-->
      <s R="{@R}" y="{@y+1}" x="{-@R}" area="{@area}"/>
    </xsl:variable><!-- Print LF-->&#10;<xsl:apply-templates 
      select="msxsl:node-set($next)"/>
  </xsl:template>

  <!-- Are we done? -->
  <xsl:template match="s[@y &gt; @R]">
    <!-- Print PI approximation -->
    <xsl:value-of select="2*@area div @R div @R"/>
  </xsl:template>

  <!-- Everything not matched above -->
  <xsl:template match="s">
    <!-- Inside the circle?-->
    <xsl:variable name="inside" select="@x*@x+@y*@y &lt; @R*@R"/>
    <!-- Print "*" or " "-->
    <xsl:choose>
      <xsl:when test="$inside">*</xsl:when>
      <xsl:otherwise>&#160;</xsl:otherwise>
    </xsl:choose>

    <xsl:variable name="next">
      <!-- Add 1 to area if we're inside the circle. Go to next column.-->
      <s R="{@R}" y="{@y}" x="{@x+1}" area="{@area+number($inside)}"/>
    </xsl:variable>
    <xsl:apply-templates select="msxsl:node-set($next)"/>
  </xsl:template>

  <!-- Begin here -->
  <xsl:template match="/R">
    <xsl:variable name="initial">
      <!-- Initial state-->
      <s R="{number()}" y="{-number()}" x="{-number()}" area="0"/>
    </xsl:variable>
    <pre>
      <xsl:apply-templates select="msxsl:node-set($initial)"/>
    </pre>
  </xsl:template>
</xsl:stylesheet>

If you want to test it, save it as pi.xslt and open the following XML file in IE:

<?xml version="1.0"?> 
<?xml-stylesheet href="pi.xslt" type="text/xsl" ?> 
<R> 
  10 
</R> 
Bautram answered 13/3, 2010 at 22:38 Comment(5)
my <eyes></eyes>! The goggles, they <do>nothing</do>!Furcate
Dang! I'm afraid you may have beaten my HyperCard solution for uniqueness :DStewardess
I can't believe you said "open...IE"Worlock
Heh, yes, back in the day, we only had IE and XML with XSLT was the solution to all our problems. Good old times! :)Krell
XSL version 1.0 wow, I remember looking forward to version 2 but by the time it came out I'd already moved on.Escheat
C
35

Perl, 95 96 99 106 109 110 119 characters:

$t+=$;=1|2*sqrt($r**2-($u-2*$_)**2),say$"x($r-$;/2).'*'x$;for 0..
($u=($r=<>)-1|1);say$t*2/$r**2

(The newline can be removed and is only there to avoid a scrollbar)

Yay! Circle version!

    $t+=$;=
 1|2*sqrt($r**
2-($u-2*$_)**2)
,say$"x($r-$;/2
).'*'x$;for 0..
($u=($r=<>)-1|1
 );$pi=~say$t*
    2/$r**2

For the uninitiated, the long version:

#!/usr/bin/perl

use strict;
use warnings;
use feature 'say';

# Read the radius from STDIN
my $radius = <>;

# Since we're only printing asterisks on lines where y is odd,
# the number of lines to be printed equals the size of the radius,
# or (radius + 1) if the radius is an odd number.
# Note: we're always printing an even number of lines.
my $maxline = ($radius - 1) | 1;

my $surface = 0;

# for ($_ = 0; $_ <= $maxline; $_++), if you wish
for (0 .. $maxline) {
    # First turn 0 ... N-1 into -(N/2) ... N/2 (= Y-coordinates),
    my $y = $maxline - 2*$_;

    # then use Pythagoras to see how many stars we need to print for this line.
    # Bitwise OR "casts" to int; and: 1 | int(2 * x) == 1 + 2 * int(x)
    my $stars = 1 | 2 * sqrt($radius**2-$y**2);
    $surface += $stars;    

    # $" = $LIST_SEPARATOR: default is a space,
    # Print indentation + stars 
    # (newline is printed automatically by say)
    say $" x ($radius - $stars/2) . '*' x $stars;
}

# Approximation of Pi based on surface area of circle:
say $surface*2/$radius**2;
Coit answered 13/3, 2010 at 22:38 Comment(22)
That is by far the most unreadable code I've seen in my entire lifeAceto
I guess you've never seen APL then.Uncouth
@Chris Marisic: Did you check the other questions/topics tagged code-golf? :) I've seen far more unreadable examples.Protection
@Peter:Unlike most, I've both seen and written APL. It takes a couple weeks to get accustomed to its special characters, but after that it can be quite readable. Even after a couple of decades to get accustomed, Perl is still much worse.Lilithe
I was only trying to be funny. I've always felt that Perl resembles nothing so much as line noise on a TTY. Some wag once dubbed it the world's first write-only language.Uncouth
So, is someone going to write an APL version then?Natoshanatron
111 chars, $r=<>;$t+=$n=1+2*int sqrt($r**2-($u-2*$_)**2),print$"x($r-$n/2).'*'x$n.$/for(0..($u=$r-1+$r%2));print$t*2/$r**2Margertmargery
@Hasturkun: Updated. Nice use of $" and $/! I wouldn't have thought of that.Coit
Using 'say' instead of print at the end of the loop would save the 3 characters used for printing newlines.Sulfaguanidine
This version is currently printing the even rows when ever R is oddTalebearer
@sundar, hmmm, I did think about that, but I tested it by saving it to file, which then requires a use... I'll leave it.Coit
You can run it using perl -M5.01Talebearer
@gnibbler, ah indeed, thanks... I'll have to think about the odd R tonight. I thought it was printing the right number of lines, though. The origin is in the center, between the middle two lines. Doesn't that mean that, for R=13, the top and bottom should be at (0,13) and (0,-13), making a total of 14 odd lines? Your example output only has 12 lines.Coit
@mercator, Since I am printing '*' only for points inside the circle the top and bottom line would be blank. You can do 14 lines if you like, the blank lines are optional.Talebearer
To this day, Perl appears to be the most compressible language on planet Earth.Turbosupercharger
@mercator, I've decided to make the odd number test case optional as it raises too many issues and violates the "fun" principleTalebearer
Change $n to some writable and inscrutable variable like $;. Then you can remove the space before for.Mink
So the C version is almost as short? So much for writing unreadable but compact Perl code I guess...Avast
@gnibbler, I don't want to shoot down my own answer now, but what exactly are the issues with the odd numbers? The only issue I can see is whether it's okay to print stars on the circle itself too or not. That isn't made clear in the challenge and I didn't think about it until your comments. That issue only happens to occur on odd radiuses because of (0, ±R) and Pythagorean triples (mathworld.wolfram.com/PythagoreanTriple.html) such as (±12, ±5) on the R=13 circle.Coit
@mercator, yeah, you are pretty spot on, and since there wasn't originally a testcase with a triple, it didn't seem fair to me to add extra conditions that would break answers already submitted. Especially as other people were basing their answers on existing ones.Talebearer
@gnibbler: instead of -M5.01, you can do -E instead. Save you four characters, if you pass it all on the command line. :)Milky
@NicholasRiley Here, sorry for the late reply :) https://mcmap.net/q/222504/-code-golf-π-dayLumpfish
A
25

FORTRAN - 101 Chars

$ f95 piday.f95 -o piday && echo 8 | ./piday


READ*,N
DO I=-N,N,2
M=(N*N-I*I)**.5
PRINT*,(' ',J=1,N-M),('*',J=0,M*2)
T=T+2*J
ENDDO
PRINT*,T/N/N
END


    READ*,N
  K=N/2*2;DO&
 I=1-K,N,2;M=&
(N*N-I*I)**.5;;
PRINT*,(' ',J=&
1,N-M),('*',J=&
0,M*2);T=T+2*J;
 ENDDO;PRINT*&
  ,T/N/N;END;
    !PI-DAY
Azriel answered 13/3, 2010 at 22:38 Comment(3)
Wait, I though formatting was important in Fortran? You have letters in column 1!Kristenkristi
Most people are still stuck on Fortan77 from what I've seen.Kristenkristi
I like how the circle version looks like the Death Star.Kc
P
22

x86 Machine Code: 127 bytes

Intel Assembler: 490 chars

    mov si,80h
    mov cl,[si]
    jcxz ret
    mov bx,10
    xor ax,ax
    xor bp,bp
    dec cx
  a:mul bx
    mov dl,[si+2]
    sub dl,48
    cmp dl,bl
    jae ret
    add ax,dx
    inc si
    loop a
    mov dl,al
    inc dl
    mov dh,al
    add dh,dh
    mov ch,dh
    mul al
    mov di,ax
  x:mov al,ch
    sub al,dl
    imul al
    mov si,ax
    mov cl,dh
  c:mov al,cl
    sub al,dl
    imul al
    add ax,si
    cmp ax,di
    mov al,32
    ja y
    or al,bl
    add bp,2
  y:int 29h
    dec cl
    jnz c
    mov al,bl
    int 29h
    mov al,13
    int 29h
    sub ch,2
    jnc x
    mov ax,bp
    cwd
    mov cl,7
  e:div di
    cmp cl,6
    jne z
    pusha
    mov al,46
    int 29h
    popa
  z:add al,48
    int 29h
    mov ax,bx
    mul dx
    jz ret
    dec cl
    jnz e
    ret

This version handles the bonus test case as well and is 133 bytes:

    mov si,80h
    mov cl,[si]
    jcxz ret
    mov bx,10
    xor ax,ax
    xor bp,bp
    dec cx
  a:mul bx
    mov dl,[si+2]
    sub dl,48
    cmp dl,bl
    jae ret
    add ax,dx
    inc si
    loop a
    mov dl,al
    rcr dl,1
    adc dl,dh
    add dl,dl
    mov dh,dl
    add dh,dh
    dec dh
    mov ch,dh
    mul al
    mov di,ax
  x:mov al,ch
    sub al,dl
    imul al
    mov si,ax
    mov cl,dh
  c:mov al,cl
    sub al,dl
    imul al
    add ax,si
    cmp ax,di
    mov al,32
    jae y
    or al,bl
    add bp,2
  y:int 29h
    dec cl
    jnz c
    mov al,bl
    int 29h
    mov al,13
    int 29h
    sub ch,2
    jnc x
    mov ax,bp
    cwd
    mov cl,7
  e:div di
    cmp cl,6
    jne z
    pusha
    mov al,46
    int 29h
    popa
  z:add al,48
    int 29h
    mov ax,bx
    mul dx
    jz ret
    dec cl
    jnz e
    ret
Pagas answered 13/3, 2010 at 22:38 Comment(2)
It's interesting that some of the high level languages have shorter character counts than the binary this produces.Beyer
@Alcari: If you included all the code in the libraries the higher level languages use, their character counts would be significantly higher. In assembler, doing printf("%f",a/b) is not trivial, there's no single instruction to do that, and my implementation above assumes that 0 <= a/b < 10 and that the operation is a division and that a and b are integers.Pagas
T
19

Python: 101 104 107 110 chars

Based on the other Python version by Nicholas Riley.

r=input()
t=0
i=1
exec"n=1+int((2*i*r-i*i)**.5)*2;t+=2.*n/r/r;print' '*(r-n/2)+'*'*n;i+=2;"*r
print t

Credits to AlcariTheMad for some of the math.


Ah, the odd-numbered ones are indexed with zero as the middle, explains everything.

Bonus Python: 115 chars (quickly hacked together)

r=input()
t=0
i=1
while i<r*2:n=1+int((2*i*r-i*i)**.5)*2;t+=2.*n/r/r;print' '*(r-n/2)+'*'*n;i+=2+(r-i==2)*2
print t
Terrorism answered 13/3, 2010 at 22:38 Comment(7)
Wow, yeah, '+' beats -1 and , any day. Yet another technique I put out of my mind because it's almost never the right thing to do :-)Natoshanatron
I've used C in the past, and never even looked at Python. This 104 chars is more readable than the C++ above. Amazing. Maybe I should learn Python...Sequent
@Dean: One of the main goals of Python is to be easy to read and write.Beyer
have you though about using exec with your 104 char answer too? :)Talebearer
I would need to roll my own compression - zlib, marshalling, etc all came out larger than the actual code.Terrorism
how about just using exec instead of the while loop? ;)Talebearer
We considered taking the compiled code object+marshal+zlib+base64 and exec that, but the result is around 350 chars. In fact, the bytecode python uses is longer than the source code itself.Beyer
S
15

In dc: 88 and 93 93 94 96 102 105 129 138 141 chars

Just in case, I am using OpenBSD and some supposedly non-portable extensions at this point.

93 chars. This is based on same formula as FORTRAN solution (slightly different results than test cases). Calculates X^2=R^2-Y^2 for every Y

[rdPr1-d0<p]sp1?dsMdd*sRd2%--
[dd*lRr-vddlMr-32rlpxRR42r2*lpxRRAP4*2+lN+sN2+dlM>y]
dsyx5klNlR/p

88 chars. Iterative solution. Matches test cases. For every X and Y checks if X^2+Y^2<=R^2

1?dsMdd*sRd2%--sY[0lM-[dd*lYd*+lRr(2*d5*32+PlN+sN1+dlM!<x]dsxxAPlY2+dsYlM>y]
dsyx5klNlR/p

To run dc pi.dc.

Here is an older annotated version:

# Routines to print '*' or ' '. If '*', increase the counter by 2
[lN2+sN42P]s1
[32P]s2
# do 1 row
# keeping I in the stack
[
 # X in the stack
 # Calculate X^2+Y^2 (leave a copy of X)
 dd*lYd*+ 
 #Calculate X^2+Y^2-R^2...
 lR-d
 # .. if <0, execute routine 1 (print '*')
 0>1
 # .. else execute routine 2 (print ' ')
 0!>2 
 # increment X..
 1+
 # and check if done with line (if not done, recurse)
 d lM!<x
]sx
# Routine to cycle for the columns
# Y is on the stack
[
  # push -X
  0lM- 

  # Do row
  lxx 
  # Print EOL
  10P
  # Increment Y and save it, leaving 2 copies
  lY 2+ dsY 
  # Check for stop condition
  lM >y
]sy
# main loop
# Push Input value
[Input:]n?
# Initialize registers
# M=rows
d sM
# Y=1-(M-(M%2))
dd2%-1r-sY
# R=M^2
d*sR
# N=0
0sN
[Output:]p
# Main routine
lyx
# Print value of PI, N/R
5klNlR/p
Scotism answered 13/3, 2010 at 22:38 Comment(4)
Doesn't work with linux dc, but I can confirm it works on openbsd. Awesome!Talebearer
@Carlos, yes the ( operator sure is handy. too bad it remains unimplemented in the dc that comes with linuxTalebearer
@Azriel - "A complete rewrite of the dc command using the bn(3) big number routines first appeared in OpenBSD 3.5." I didn't know that. Some nice new operators are included, but they are marked as "non-portable extensions".Feebleminded
Yeah, the ( operator alone allowed to shed 6 strokes!Scotism
B
12

Powershell, 119 113 109 characters

($z=-($n=$args[($s=0)])..$n)|?{$_%2}|%{$l="";$i=$_
$z|%{$l+=" *"[$i*$i+$_*$_-lt$n*$n-and++$s]};$l};2*$s/$n/$n

and here's a prettier version:

( $range = -( $R = $args[ ( $area = 0 ) ] ) .. $R ) | 
  where { $_ % 2 } |
  foreach {
    $line = ""
    $i = $_
    $range | foreach {
        $line += " *"[ $i*$i + $_*$_ -lt $R*$R -and ++$area ]
    }
    $line
 }
 2 * $area / $R / $R
Bautram answered 13/3, 2010 at 22:38 Comment(1)
@Thor: I hope not, but this must be the ugliest thing I've ever written :)Krell
M
10

Ruby, 96 chars

(based on Guffa's C# solution):

r=gets.to_f
s=2*t=r*r
g=1-r..r
g.step(2){|y|g.step{|x|putc' * '[i=t<=>x*x+y*y];s+=i}
puts}
p s/t

109 chars (bonus):

r=gets.to_i
g=-r..r
s=g.map{|i|(g.map{|j|i*i+j*j<r*r ?'*':' '}*''+"\n")*(i%2)}*''
puts s,2.0/r/r*s.count('*')
Melvinmelvina answered 13/3, 2010 at 22:38 Comment(3)
Thanks! I'm embarrassed to see how unreadable Ruby can be... :)Electromagnetic
you can also use p s instead of puts s :)Talebearer
Nice fresh ideas in there - I like that you are using g with 2 different step sizes and the <=> to avoid having code to convert from logicalTalebearer
Z
10

Haskell 139 145 147 150 230 chars:

x True=' ';x _='*'
a n=unlines[[x$i^2+j^2>n^2|j<-[-n..n]]|i<-[1-n,3-n..n]]
b n=a n++show(sum[2|i<-a n,i=='*']/n/n)
main=readLn>>=putStrLn.b

Handling the odd numbers: 148 chars:

main=do{n<-readLn;let{z k|k<n^2='*';z _=' ';c=[[z$i^2+j^2|j<-[-n..n]]|i<-[1,3..n]];d=unlines$reverse c++c};putStrLn$d++show(sum[2|i<-d,i=='*']/n/n)}

150 chars: (Based on the C version.)

a n=unlines[concat[if i^2+j^2>n^2then" "else"*"|j<-[-n..n]]|i<-[1-n,3-n..n]]
main=do n<-read`fmap`getLine;putStr$a n;print$2*sum[1|i<-a n,i=='*']/n/n

230 chars:

main=do{r<-read`fmap`getLine;let{p=putStr;d=2/fromIntegral r^2;l y n=let c m x=if x>r then p"\n">>return m else if x*x+y*y<r*r then p"*">>c(m+d)(x+1)else p" ">>c m(x+1)in if y>r then print n else c n(-r)>>=l(y+2)};l(1-r`mod`2-r)0}

Unminified:

main = do r <- read `fmap` getLine
          let p = putStr
              d = 2/fromIntegral r^2
              l y n = let c m x = if x > r
                                  then p "\n" >> return m
                                  else if x*x+y*y<r*r
                                       then p "*" >> c (m+d) (x+1)
                                       else p " " >> c m (x+1)
                      in if y > r
                         then print n
                         else c n (-r) >>= l (y+2)
          l (1-r`mod`2-r) 0

I was kinda hoping it would beat some of the imperative versions, but I can't seem to compress it any further at this point.

Zoogeography answered 13/3, 2010 at 22:38 Comment(7)
Chopped off 2 more by getting rid of the "d" and adding 1 instead of it and then printing "2*n/fromIntegral r^2"Zoogeography
Shaved 3 characters off via a few Haskell tricks. I love that in Haskell there is often no cost to multiple lines (newline vs. semicolon) and hence our code-golf is generally readable!Ralina
Strictly speaking, the 145-char version only works if the input is even. But very nice either way.Zoogeography
Shortened the I/O line. It should still be possible to save a few more characters by pushing the function defs into a main=do{...let{...}...} block, I think.Test
@comingstorm: Cool! I didn't know about readLn. This will help many a Haskell code-golf. @Steve: Yup, I'm still trying to figure out the most efficient way to fix that.Ralina
How about x y|y=' '|0<1='*'for x True=' ';x _='*'?Nasal
@FUZxxl x b|b=' ';x _='*' is another suggestion, same length as yours. I also like x b=last$'*':[' '|b], but it is three characters longer...Maddis
S
10

HyperTalk: 237 characters

Indentation is not required nor counted. It is added for clarity. Also note that HyperCard 2.2 does accept those non-ASCII relational operators I used.

function P R
  put""into t
  put 0into c
  repeat with i=-R to R
    if i mod 2≠0then
      repeat with j=-R to R
        if i^2+j^2≤R^2then
          put"*"after t
          add 1to c
        else
          put" "after t
        end if
      end repeat
      put return after t
    end if
  end repeat
  return t&2*c/R/R
end P

Since HyperCard 2.2 doesn't support stdin/stdout, a function is provided instead.

Stewardess answered 13/3, 2010 at 22:38 Comment(4)
Hypercard, Mr. Adams? Seriously? This is highly unexpected.Stacee
@Kawa: That's kind of why I posted it :) Also, code golf is a good way to build up a test suite in case I decide to write a HyperTalk interpreter in the future.Stewardess
Hah! I'd like to see that, XDStacee
If you ever decide to write that interpreter, or want to join work on an existing one, let me know and I can add mention of it on hypercard.org and I'd be curious about how it goes :-)Farmstead
T
10

C#: 209 202 201 characters:

using C=System.Console;class P{static void Main(string[]a){int r=int.Parse(a[0]),s=0,i,x,y;for(y=1-r;y<r;y+=2){for(x=1-r;x<r;s+=i)C.Write(" *"[i=x*x+++y*y<=r*r?1:0]);C.WriteLine();}C.Write(s*2d/r/r);}}

Unminified:

using C = System.Console;
class P {
  static void Main(string[] arg) {
    int r = int.Parse(arg[0]), sum = 0, inside, x, y;
    for (y = 1 - r; y < r; y += 2) {
      for (x = 1 - r; x < r; sum += inside)
        C.Write(" *"[inside = x * x++ + y * y <= r * r ? 1 : 0]);
      C.WriteLine();
    }
    C.Write(sum * 2d / r / r);
  }
}
Tomlinson answered 13/3, 2010 at 22:38 Comment(7)
I don't know C# very much but shouldn't you able to use string[]a and 1-r (instead of -1+r)?Gabionade
@Kenny: You are right. :) That saves three characters, and then I managed to get rid of five more.Tomlinson
Spotted that first thing, totally missed on the -r+1 thingy.Fessler
Also, spotted x*xx+++y*y too, but it is a mad thing to dissect at first glance.Fessler
I took the liberty of eliminating another byte ;-)Pilothouse
Nice one. Applied it to the non-compacted once too.Fessler
Using goto I can get to 202 characters though... a:[...]goto a; But unable to eliminate the loose snippets from the for.Fessler
S
9

PHP: 117

Based on dev-null-dweller

for($y=1-$r=$argv[1];$y<$r;$y+=2,print"\n")for($x=1-$r;$x<$r;$x++)echo$r*$r>$x*$x+$y*$y&&$s++?'*':' ';echo$s*2/$r/$r;
Starchy answered 13/3, 2010 at 22:38 Comment(0)
A
8

You guys are thinking way too hard.

switch (r) {
   case 1,2:
      echo "*"; break;
   case 3,4:
      echo " ***\n*****\n ***"; break;
   // etc.
}
Agitation answered 13/3, 2010 at 22:38 Comment(5)
Character count gets a bit out of hand, don't you think? :)Talebearer
Doesn't scale. Unmaintainable!Snuffbox
I tried compressing the test case cheat as much as possible and it still ended up slightly larger than my actual solution :PTerrorism
+1, always do the most obvious thing first... if someone doesnt like it, loudly complain that the spec wasnt clear enoughIchor
Brian had a semi-serious attempt at special casing the test cases, you should upvote his too if you like this answer ;) stackoverflow.com/questions/2457995Talebearer
H
7

J: 47, 46, 45

Same basic idea as other solutions, i.e. r^2 <= x^2 + y^2, but J's array-oriented notation simplifies the expression:

c=:({&' *',&":2*+/@,%#*#)@:>_2{.\|@j./~@i:@<:

You'd call it like c 2 or c 8 or c 10 etc.

Bonus: 49

To handle odd input, e.g. 13, we have to filter on odd-valued x coordinates, rather than simply taking every other row of output (because now the indices could start at either an even or odd number). This generalization costs us 4 characters:

c=:*:({&' *'@],&":2%(%+/@,))]>(|@j./~2&|#])@i:@<:

Deminimized version:

c =: verb define
  pythag   =. y > | j./~ i:y-1    NB.  r^2 > x^2 + y^2
  squished =. _2 {.\ pythag       NB.  Odd rows only
  piApx    =. (2 * +/ , squished) %  y*y
  (squished { ' *') , ": piApx
)

Improvements and generalizations due to Marshall Lochbam on the J Forums.

Hippel answered 13/3, 2010 at 22:38 Comment(0)
N
5

Python: 118 characters

Pretty much a straightforward port of the Perl version.

r=input()
u=r+r%2
t=0
for i in range(u):n=1+2*int((r*r-(u-1-2*i)**2)**.5);t+=n;print' '*(r-n/2-1),'*'*n
print 2.*t/r/r
Natoshanatron answered 13/3, 2010 at 22:38 Comment(3)
For python2 you can just use r=input()Talebearer
You don't need the space between print and ' 'Talebearer
OK, that's scary, it's shorter than the Perl version now. (I completely put "input" out of my mind because it's so unsafe ordinarily...)Natoshanatron
P
4

C++: 169 characters

#include <iostream>
int main(){int i,j,c=0,n;std::cin>>n;for(i=-n;i<=n;i+=2,std::cout<<'\n')for(j=-n;j<=n;j++)std::cout<<(i*i+j*j<=n*n?c++,'*':' ');std::cout<<2.*c/n/n;}

Unminified:

#include <iostream>
int main()
{
    int i,j,c=0,n;
    std::cin>>n;
    for(i=-n;i<=n;i+=2,std::cout<<'\n')
        for(j=-n;j<=n;j++)
            std::cout<<(i*i+j*j<=n*n?c++,'*':' ');
    std::cout<<2.*c/n/n;
}

(Yes, using std:: instead of using namespace std uses less characters)

The output here doesn't match the test cases in the original post, so here's one that does (written for readability). Consider it a reference implementation (if Poita_ doesn't mind):

#include <iostream>
using namespace std;

int main()
{
    int i, j, c=0, n;
    cin >> n;
    for(i=-n; i<=n; i++) {
        if (i & 1) {
            for(j=-n; j<=n; j++) {
                if (i*i + j*j <= n*n) {
                    cout << '*';
                    c++;
                } else {
                    cout << ' ';
                }
            }
            cout << '\n';
        }
    }
    cout << 2.0 * c / n / n << '\n';
}

C++: 168 characters (with output I believe is correct)

#include <iostream>
int main(){int i,j,c=0,n;std::cin>>n;for(i=-n|1;i<=n;i+=2,std::cout<<"\n")for(j=-n;j<=n;j++)std::cout<<" *"[i*i+j*j<=n*n&&++c];std::cout<<2.*c/n/n;}
Palpebrate answered 13/3, 2010 at 22:38 Comment(13)
The code loops from -n to n, so for an input of for example 4 it displays a diameter of 9, not 7 as shown in the test cases.Tomlinson
Is it a requirement that your circle matches the OP's exactly?Palpebrate
@Poita_, Yes the asterisks should match exactly for the test cases given. Extra whitespace to the right doesn't matter thoughTalebearer
You may wish to change it to #include <iostream.h> which basically is #include <iostream> -- using namespace std; for compatibility with old C++ compilers.Transfer
what is the & operator doing in line 9 -> " if (i & 1) "Intranuclear
@Carlos, I didn't write that particular bit, but it's a binary AND operator. It checks that the last bit is set, which is equivalent to doing i%2, but is "faster". It's not really faster because the compiler would do it anyway.Palpebrate
@Poita_: Actually, i%2 and i&1 behave differently with negative numbers. (-1)&1 is 1, which is what we want here. (-1)%2 is -1 on my system, and this conforms to C99. Thus, although if (i&1) and if (i%2) will do the same thing, one must be careful with if (i%2 == 1), which won't work when i is negative.Stewardess
Sometimes the different precedence of & vs % can be exploited for golfingTalebearer
You can save at least 8 characters if you use "#define o std::cout<<" and then replace all "std::cout<<" with "o "Kweisui
Wouldn't puts() give you 10 fewer characters?Lingual
@Robert, no because that requires that you include stdlib.h.Palpebrate
@Poita That depends on the compiler/linker. GCC 4.3.3 does not require any includes to use puts. I can do it with printf too, but I actually get a warning [int printf(const char*) != int printf(const char*,...)]. Any undeclared c-function defaults to returning int and taking whatever arguments it is used with. The linker then has to figure out the implementation of int puts(const char*). Since gcc always links against standard libs (unless -nostdlib) this is easy.Tubuliflorous
Well I think it's only fair that the code does not depend on compiler idiosyncrasies.Palpebrate
L
3

APL: 59

This function accepts a number and returns the two expected items. Works correctly in bonus cases.

{⍪(⊂' *'[1+m]),q÷⍨2×+/,m←(2|v)⌿(q←⍵*2)>v∘.+v←2*⍨⍵-⍳1+2×⍵-1}

Dialect is Dyalog APL, with default index origin. Skill level is clueless newbie, so if any APL guru wants to bring it down to 10 characters, be my guest!


You can try it online on Try APL, just paste it in and put a number after it:

   {⍪(⊂' *'[1+m]),q÷⍨2×+/,m←(2|v)⌿(q←⍵*2)>v∘.+v←2*⍨⍵-⍳1+2×⍵-1} 13
      *************
   *******************
  *********************
 ***********************
*************************
*************************
*************************
*************************
 ***********************
  *********************
   *******************
      *************
2.98225
Lumpfish answered 13/3, 2010 at 22:38 Comment(2)
Although I dont know APL, It looks prettier than the J version.Tuque
@Tuque Indeed. APL is beautiful, both conceptually and aesthetically. I started learning J, but was turned off by the random ASCII craziness. A good soul wrote an open source APL interpreter for Node.js (npm install apl) that's pretty good. It computes the above code with just a minor change (no monadic , 2nd char.) You can find good APL documentation on all vendor sites, such as Dyalog.Lumpfish
P
3

Ruby 1.8.x, 93

r=$_.to_f
q=0
e=r-1
(p(('*'*(n=1|2*(r*r-e*e)**0.5)).center r+r)
q+=n+n
e-=2)while-r<e
p q/r/r

Run with $ ruby -p piday

Pancratium answered 13/3, 2010 at 22:38 Comment(3)
Nice one, but it doesn't print out the pi approximationTalebearer
It doesn't work in 1.9.1, and prints double quotes around the circle.Electromagnetic
It's normal for golf programs not to work on a wildly different language levels. How many Perl or Python c-g's work on every version of the language? It is interesting, though, turns out the reason is because Integer|Float no longer coerces the float on 1.9.Pancratium
C
3

PHP: 126 132 138

(based on Guffa C# solution)

126:

for($y=1-($r=$argv[1]);$y<$r;$y+=2,print"\n")for($x=1-$r;$x<$r;$s+=$i,++$x)echo($i=$x*$x+$y*$y<=$r*$r)?'*':' ';echo$s*2/$r/$r;

132:

for($y=1-($r=$argv[1]);$y<$r;$y+=2){for($x=1-$r;$x<$r;@$s+=$i,++$x)echo($i=$x*$x+$y*$y<=$r*$r?1:0)?'*':' ';echo"\n";}echo$s*2/$r/$r;

138:

for($y=1-($r=$argv[1]);$y<$r;$y+=2){for($x=1-$r;$x<$r;@$s+=$i){$t=$x;echo($i=$t*$x++ +$y*$y<=$r*$r?1:0)?'*':' ';}echo"\n";}echo$s*2/$r/$r;

Current full:

for( $y = 1 - ( $r = $argv[1]); $y < $r; $y += 2, print "\n")
    for( $x = 1-$r; $x < $r; $s += $i, ++$x)
        echo( $i = $x*$x + $y*$y <= $r*$r) ? '*' : ' ';
echo $s*2 /$r /$r;

Can be without @ before first $s but only with error_reporting set to 0 (Notice outputs is messing the circle)

Commodus answered 13/3, 2010 at 22:38 Comment(2)
what does the /$r do in echo $s*2 /$r /$r;Traumatism
OHH division... the spacing threw me off, thought it was some operator shorthand i'd never seenTraumatism
G
2

bc: 165, 127, 126 chars

Based on the Python version.

r=read()
for(i=-1;r*2>i+=2;scale=6){n=sqrt(2*i*r-i*i)
scale=0
n=1+n/1*2
j=r-n/2
t+=2*n
while(j--)" "
while(n--)"*"
"
"}
t/r/r

(New line after the last line cannot be omitted here.)

Gloria answered 13/3, 2010 at 22:38 Comment(2)
127 chars: r=read();for(i=1;i<r*2;scale=6){n=sqrt(2*ir-ii);scale=0;n=1+n/1*2;i+=2;j=r-n/2;t+=2*n;while(j--)" ";while(n--)"*";" "};t/r/rFeebleminded
The only problem here is that it now fails for 0, but according to current rules, it's ok.Gloria
B
2

Python: 148 characters.

Failed (i.e. not short enough) attempt to abuse the rules and hardcode the test cases, as I mentioned in reply to the original post. Abusing it with a more verbose language may have been easier:

a=3.0,3.125,3.16
b="1","23","3677","47899"
r=input()
for i in b[r/3]+b[r/3][::-1]:q=1+2*int(i);print ' '*(int(b[r/3][-1])-int(i))+'*'*q
print a[r/5]
Buehler answered 13/3, 2010 at 22:38 Comment(0)
S
2

And a bash entry: 181 186 190 chars

for((y=-(r=$1,r/2*2);y<=r;y+=2));do for((x=-r;x<=r;++x));do((x*x+y*y<r*r))&&{((++n));echo -n '*';}||echo -n " ";((x<r))||echo;done;done;((s=1000,p=n*2*s/r/r,a=p/s,b=p%s));echo $a.$b

Run with e.g. bash py.sh 13

Scotism answered 13/3, 2010 at 22:38 Comment(0)
C
2

JavaScript (SpiderMonkey) - 118 chars

This version accepts input from stdin and passes the bonus test cases

r=readline()
for(t=0,i=-r;i<r;i++)if(i%2){for(s='',j=-r;j<r;j++){t+=q=i*i+j*j<r*r
s+=q?'*':' '}print(s)}print(t*2/r/r)

Usage: cat 10 | js thisfile.js -- jsbin preview adds an alias for print/readline so you can view in browser

Javascript: 213 163


Updated

r=10;m=Math;a=Array;t=0;l=document;for(i=-r;i<r;i+=2){w=m.floor(m.sqrt(r*r-i*i)*2);t+=w*2;l.writeln(a(m.round(r-w/2)).join(' ')+a(w).join('*'));}l.writeln(t/(r*r))

Nobody said it had to render correctly in the browser - just the output. As such I've removed the pre tags and optimised it further. To view the output you need to view generated source or set your stylesheet accordingly. Pi is less accurate this way, but it's now to spec.


r=10;m=Math;a=Array;t=0;s='';for(i=-r;i<r;i++){w=m.floor((m.sqrt(m.pow(r,2)-m.pow(i,2)))*2);t+=w;if(i%2){z=a(m.round(r-w/2)).join(' ')+a(w).join('*');s+=z+'\n';}}document.write('<pre>'+(s+(t/m.pow(r,2)))+'</pre>')

Unminified:

r=10;
m=Math;
a=Array;
t=0;
s='';
for(i=-r;i<r;i++){
    w=m.floor((m.sqrt(m.pow(r,2)-m.pow(i,2)))*2);
    t+=w;
    if(i%2){
    z=a(m.round(r-w/2)).join(' ')+a(w).join('*');
    s+=z+'\n';
    }
}
document.write('<pre>'+(s+(t/m.pow(r,2)))+'</pre>');
Capriola answered 13/3, 2010 at 22:38 Comment(0)
G
1

GAWK: 136, 132, 126, 125 chars

Based on the Python version.

{r=$1
for(i=-1;r*2>i+=2;print""){n=1+int((2*i*r-i*i)**.5)*2
t+=2*n/r/r
printf"%*s",r-n/2,""
while(n--)printf"%c","*"}print t}
Gloria answered 13/3, 2010 at 22:38 Comment(0)
A
1

Java: 234

class C{public static void main(String[] a){int x,y,s=0,r=Integer.parseInt(a[0]);for(y=1-r;y<r;y+=2){for(x=1-r;x<r;++x){boolean b=x*x+y*y<=r*r;s+=b?1:0;System.out.print(b?'*':' ');}System.out.println();}System.out.println(s*2d/r/r);}}

Unminified:

class C{
    public static void main(String[] a){
        int x,y,s=0,r=Integer.parseInt(a[0]); 
        for(y=1-r;y<r;y+=2){
            for(x=1-r;x<r;++x) {
                boolean b=x*x+y*y<=r*r;
                s+=b?1:0;
                System.out.print(b?'*':' ');
            }
            System.out.println();
        }
        System.out.println(s*2d/r/r);
    }
}
Atlantis answered 13/3, 2010 at 22:38 Comment(1)
Could probably save ~50 characters rewriting this in scalaArtemus

© 2022 - 2024 — McMap. All rights reserved.