Numbers as Circular Graphics

36

6

First, study this puzzle to get a feel for what you will be producing.

Your challenge is to write a program or function which will output a circular graphic like the ones from the puzzle, given a (base 10) number between 1 and 100 (inclusive). This is similar to this challenge, except that you will be producing a graphic rather than roman numerals. The following circles represent the numbers 1-10, from left to right:

circle pattern

As the answer to the puzzle states, your graphic should read like a roman numeral from the inside-out, where the line thickness represents the roman numeral symbols and the entire graphic represents the number. For your reference, here are the line thicknesses which you will need. Each line should have a 3px padding between it and the next.

Number  Roman Numeral   Line Width
1       I               1px
5       V               3px
10      X               5px
50      L               7px
100     C               9px

Please post a sample or two of your output. Assume input is correct, standard loopholes, etc and so forth. This is code golf, so fewest bytes win. In the event of a tie, most votes win. Good luck!

Rip Leeb

Posted 2014-11-26T02:13:09.363

Reputation: 1 250

3Is the correct absolute size of the image necessary, or is it sufficient to have the right relative sizes? – David Zhang – 2014-11-26T07:43:19.230

@DavidZhang Yes, please stick to the line and padding sizes that I listed, for fairness sake. – Rip Leeb – 2014-11-26T12:38:36.383

Answers

15

Mathematica - 166 181 bytes

A bit more concise than the other Mathematica answer, thanks in part to a more point-free style.

c = Characters; r = Riffle;
Graphics[r[{0, 0}~Disk~# & /@ Reverse@Accumulate[
    l = {3} ~Join~ r[2 Position[c@"IVXLC", #][[1, 1]] - 1 & /@ 
        c@IntegerString[#, "Roman"], 3]], {White, Black}],
    ImageSize -> 2 Total@l] &

All whitespace is for clarity only. This defines an anonymous function which returns the desired graphic.

Animation

Animated circles

Generating an animated GIF of the number circles is trivial in Mathematica, which has built-in functions for animating and exporting sequences of arbitrary objects. Assuming the above code has just been executed,

Table[Show[%@n, PlotRange -> {{-100, 100}, {-100, 100}}, 
    ImageSize -> 200], {n, 1, 399, 1}];
Export["animcircles.gif", %]

Example Output

Example output

David Zhang

Posted 2014-11-26T02:13:09.363

Reputation: 348

Maybe related to the wiggling: http://mathematica.stackexchange.com/q/134272

– coredump – 2016-12-26T15:42:04.407

Please post a few results. Sorry for not asking this is the first place. I've also changed the question to accept functions. – Rip Leeb – 2014-11-26T12:40:06.580

Thanks for the suggestions @MartinBüttner. The code has been fixed to output correctly-sized images, and example output has been added. – David Zhang – 2014-11-26T17:17:00.750

3Your animation wiggles. Not that I could do better. – corsiKa – 2014-11-27T20:35:24.287

Hmm, you're right. I'm really not sure why it does that, considering I specified the plot range explicitly for Mathematica. – David Zhang – 2014-11-28T19:24:29.617

15

Common Lisp - 376 331 304 bytes

(use-package(car(ql:quickload'vecto)))(lambda(n o &aux(r 3)l p)(map()(lambda(c)(setf l(position c" I V X L C D M")p(append`((set-line-width,l)(centered-circle-path 0 0,(+(/ l 2)r))(stroke))p)r(+ r l 3)))(format()"~@R"n))(with-canvas(:width(* 2 r):height(* 2 r))(translate r r)(map()'eval p)(save-png o)))

Examples

enter image description here (1) enter image description here (24)

enter image description here (104) enter image description here (1903) enter image description here (3999)

Animation

For numbers from 1 to 400:

New

NB: For the record, this animation is done as follows:

I have a modified version of the code, named rings which returns the width of the produced image. Hence, the result of the the following loop is the maximum size, here 182:

 (loop for x from 1 to 400
       maximize (rings x (format nil "/tmp/rings/ring~3,'0d.png" x)))

The whole loop takes 9.573 seconds. That gives approximately 24ms for each integer. Then, in a shell:

 convert -delay 5 -loop 0 -gravity center -extent 182x182 ring*png anim.gif

Ungolfed

(ql:quickload :vecto)
(use-package :vecto)

(lambda (n o)
  (loop with r = 3
        for c across (format nil "~@R" n)
        for l = (1+ (* 2(position c"IVXLCDM")))
        for h = (/ l 2)
        collect `(,(incf r h),l) into p
        do (incf r (+ h 3))
        finally (with-canvas(:width (* 2 r) :height (* 2 r))
                  (loop for (x y) in p
                        do (set-line-width y)
                           (centered-circle-path r r x)
                           (stroke))
                  (save-png o))))

Explanations

  • The function takes an integer N between 1 and 3999 and a filename

  • I use (format nil "~@R" N) to convert from decimal to roman. For example:

     (format nil "~@R" 34) => "XXXIV"
    

    The ~@R format control string is specified to work for integers between 1 and 3999. That's why there is a limitation for the range of allowed inputs.

  • I iterate over the resulting string to build a list P containing (radius width) couples, for each numeral C.

    • The width is a simple linear mapping: I use the constant string "IVXLCDM" to compute the position of C in it. Multiplying by two and adding one, we obtain the desired value:

             (1+ (* 2 (position c "IVXLCDM")))
      

      This is however done slightly differently in the golfed version:

             (position c " I V X L C D M")
      
    • The computation of each radius takes into account the width of each ring as well as empty spaces between rings. Without any speed optimization, computations remain precise because they are not based on floats, but rational numbers.

      Edit: I changed the parameters to comply with the padding rules.

  • Once this is done, I know the required size of the resulting canvas (twice the latest computed radius).

  • Finally, I draw a circle for each element of P and save the canvas.

coredump

Posted 2014-11-26T02:13:09.363

Reputation: 6 292

1"This code supports all roman numerals (IVXLCDM)". Does that mean your program takes roman numerals as input? That's not what I intended, but pretty cool. Props for the animation too. – Rip Leeb – 2014-11-26T12:45:41.213

1No, no, sorry if this is unclear: it works for any integer between 1 and 3999. In your question, you only required inputs from 1 to 100, and your table does not mention D or M... I'll edit that part. – coredump – 2014-11-26T12:51:48.600

8

HTML+JQuery, 288

HTML

<canvas>

JS

    r=3;w=9;c=$('canvas').get(0).getContext('2d')
    for(i=prompt(),e=100;e-.1;e/=10){
    if((x=Math.floor(i/e)%10)==4)d(w)+d(w+2)
    else if(x==9)d(w)+d(w+4)
    else{if(x>4)d(w+2)
    for(j=x%5;j;j--)d(w)}
    w-=4}
    function d(R){c.lineWidth=R
    c.beginPath()
    c.arc(150,75,r+=R/2,0,7)
    c.stroke()
    r+=R/2+3}

r=3;w=9;c=$('canvas').get(0).getContext('2d')
for(i=prompt(),e=100;e-.1;e/=10){
if((x=Math.floor(i/e)%10)==4)d(w)+d(w+2)
else if(x==9)d(w)+d(w+4)
else{if(x>4)d(w+2)
for(j=x%5;j;j--)d(w)}
w-=4}
function d(R){c.lineWidth=R
c.beginPath()
c.arc(150,75,r+=R/2,0,7)
c.stroke()
r+=R/2+3}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<canvas>

Fiddle

TwiNight

Posted 2014-11-26T02:13:09.363

Reputation: 4 187

No stack snippet ? – Optimizer – 2014-11-26T13:27:36.567

@Optimizer Totally forgot we have that now – TwiNight – 2014-11-26T13:38:00.203

5

Java, 565

import java.awt.*;class Z{public static void main(String[]s){int i=new Byte(s[0]),j=i/10,k=i%10;String t="",u;if(j>8)t="59";if(j>9)t="9";if(j==4)t="57";else if(j<9){t=j>4?"7":"";j-=j>4?5:0;if(j>0)t+="5";if(j>1)t+="5";if(j>2)t+="5";}if(k>8)t+="15";if(k==4)t+="13";else if(k<9){t+=k>4?"3":"";k-=k>4?5:0;if(k>0)t+="1";if(k>1)t+="1";if(k>2)t+="1";}u=t;Frame f=new Frame(){public void paint(Graphics g){g.setColor(Color.BLACK);int x=0;for(char c:u.toCharArray()){int z=c-48,q=x;for(;x<q+z;)g.drawOval(99-x,99-x,x*2,x++*2);x+=3;}}};f.setSize(200,200);f.setVisible(1>0);}}

Examples

15

15

84

84

93

93

Formatted nicely:

import java.awt.*;    
class Z {    
    public static void main(String[] s) {
        int i = new Byte(s[0]), j = i / 10, k = i % 10;
        String t = "", u;
        if (j > 8)
            t = "59";
        if (j > 9)
            t = "9";
        if (j == 4) {
            t = "57";
        } else if (j < 9) {
            t = j > 4 ? "7" : "";
            j -= j > 4 ? 5 : 0;
            if (j > 0)
                t += "5";
            if (j > 1)
                t += "5";
            if (j > 2)
                t += "5";
        }
        if (k > 8)
            t += "15";
        if (k == 4) {
            t += "13";
        } else if (k < 9) {
            t += k > 4 ? "3" : "";
            k -= k > 4 ? 5 : 0;
            if (k > 0)
                t += "1";
            if (k > 1)
                t += "1";
            if (k > 2)
                t += "1";
        }
        u = t;
        Frame f = new Frame() {
            public void paint(Graphics g) {
                g.setColor(Color.BLACK);
                int x = 0;
                for (char c : u.toCharArray()) {
                    int z = c - 48, q = x;
                    for (; x < q + z;) {
                        g.drawOval(99 - x, 99 - x, x * 2, x++ * 2);
                    }
                    x += 3;
                }
            }
        };
        f.setSize(200, 200);
        f.setVisible(1 > 0);
    }
}

Ypnypn

Posted 2014-11-26T02:13:09.363

Reputation: 10 485

Please post a few results. Sorry for not asking this is the first place. – Rip Leeb – 2014-11-26T12:39:44.843

3

Mathematica 9 - 301 249 bytes

:D It feels cheaty to use the built-in converting to Roman numerals, but hey.

l=Length;k=Characters;r@n_:=(w=Flatten[Position[k@"IVXLC",#]*2-1&/@k@IntegerString[n,"Roman"]];Show[Table[Graphics@{AbsoluteThickness@w[[i]],Circle[{0,0},(Join[{0},Accumulate[3+w]]+3)[[i]]+w[[i]]/2]},{i,Range@l@w}],ImageSize->{(Total@w+(l@w)*3)*2}])

(When I did this last night I didn't have much time, but I realized it could be golfed down way more. And I also took some hints from David Zhang... :D Thanks!)

A bit more clearly:

l=Length;
k=Characters;
r@n_:=
    (
    w=Flatten[Position[k@"IVXLC",#]*2-1&/@k@IntegerString[n,"Roman"]];
    Show[Table[Graphics@{AbsoluteThickness@w[[i]],Circle[{0,0},(Join[{0},Accumulate[3+w]]+3)[[i]]+w[[i]]/2]},{i,Range@l@w}],ImageSize->{(Total@w+(l@w)*3)*2}]
    )

This is a function that you can call like this:

r[144]

enter image description here

Or, you can show the results from values a to b with: Table[r[i],{i,a,b}]

Note: This only works for values up to 399.

kukac67

Posted 2014-11-26T02:13:09.363

Reputation: 2 159

1

Python 2, 322 296

The script reads the number to be converted from stdin, and outputs the image as SVG markup.

.. I use 'red' instead of 'black', because it saves 2 chars :)

Here are some samples : for 23 : http://jsfiddle.net/39xmpq49/ for 42 : http://jsfiddle.net/7Ls24q9e/1/

i=input();r=9
def R(n,p):
 global r,i;i-=n;print '<circle r="{0}" stroke-width="{1}"/>'.format(r,p);r+=p+3
print '<svg viewBox="-50 -50 99 99" fill="none" stroke="red">',[[R(n,int(p)) for p in s*int(i/n)] for n,s in zip([100,90,50,40,10,9,5,4,1],'9/59/7/57/5/15/3/13/1'.split('/'))]and'','</svg>'

dieter

Posted 2014-11-26T02:13:09.363

Reputation: 2 010

1

JavaScript 342 334 308

function R(n){var v=document,o=[],x=1,c=v.body.appendChild(v.createElement('canvas')).getContext('2d')
while(n)v=n%10,y=x+2,o=[[],[x],[x,x],[x,x,x],[x,y],[y],[y,x],[y,x,x],[y,x,x,x],[x,x+=4]][v].concat(o),n=(n-v)/10
v=3
while(x=o.shift())c.lineWidth=x,c.beginPath(),c.arc(150,75,v+x/2,0,7),c.stroke(),v+=x+3}

for (var i = 1; i <= 100; i++) {
  R(i);
}

wolfhammer

Posted 2014-11-26T02:13:09.363

Reputation: 1 219