Números como gráficos circulares

36

Primero, estudie este rompecabezas para tener una idea de lo que va a producir.

Su desafío es escribir un programa o función que genere un gráfico circular como los del rompecabezas, dado un número (base 10) entre 1 y 100 (inclusive). Esto es similar a este desafío , excepto que producirá un gráfico en lugar de números romanos. Los siguientes círculos representan los números del 1 al 10, de izquierda a derecha:

patrón circular

Como dice la respuesta al acertijo, su gráfico debe leerse como un número romano desde adentro hacia afuera, donde el grosor de la línea representa los símbolos del número romano y todo el gráfico representa el número. Para su referencia, aquí están los grosores de línea que necesitará. Cada línea debe tener un relleno de 3px entre ella y la siguiente.

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

Por favor, publique una muestra o dos de su salida. Suponga que la entrada es correcta, lagunas estándar , etc., etc. Este es el código de golf, por lo que ganan menos bytes. En caso de empate, la mayoría de los votos ganan. ¡Buena suerte!

Rip Leeb
fuente
3
¿Es necesario el tamaño absoluto correcto de la imagen, o es suficiente tener los tamaños relativos correctos?
David Zhang
@DavidZhang Sí, por favor, respete la línea y los tamaños de relleno que enumeré.
Rip Leeb

Respuestas:

15

Mathematica - 166 181 bytes

Un poco más conciso que la otra respuesta de Mathematica, gracias en parte a un estilo más libre de puntos.

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] &

Todo el espacio en blanco es solo por claridad. Esto define una función anónima que devuelve el gráfico deseado.

Animación

Círculos animados

Generar un GIF animado de los círculos numéricos es trivial en Mathematica, que tiene funciones incorporadas para animar y exportar secuencias de objetos arbitrarios. Suponiendo que el código anterior se acaba de ejecutar,

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

Salida de ejemplo

Salida de ejemplo

David Zhang
fuente
Por favor, publique algunos resultados. Perdón por no preguntar, este es el primer lugar. También he cambiado la pregunta para aceptar funciones.
Rip Leeb
Gracias por las sugerencias @ MartinBüttner. El código se ha corregido para generar imágenes de tamaño correcto y se ha agregado un resultado de ejemplo.
David Zhang el
3
Tu animación se mueve. No es que pueda hacerlo mejor.
corsiKa
Hmm, tienes razón. Realmente no estoy seguro de por qué hace eso, considerando que especifiqué el rango de la trama explícitamente para Mathematica.
David Zhang
Tal vez relacionado con el meneo: mathematica.stackexchange.com/q/134272
coredump
15

Lisp común 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)))

Ejemplos

ingrese la descripción de la imagen aquí(1) ingrese la descripción de la imagen aquí(24)

ingrese la descripción de la imagen aquí(104) ingrese la descripción de la imagen aquí(1903) ingrese la descripción de la imagen aquí(3999)

Animación

Para números del 1 al 400:

Nuevo

NB: Para el registro, esta animación se realiza de la siguiente manera:

Tengo una versión modificada del código, ringscuyo nombre devuelve el ancho de la imagen producida. Por lo tanto, el resultado del siguiente bucle es el tamaño máximo, aquí 182 :

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

Todo el ciclo toma 9.573 segundos. Eso da aproximadamente 24 ms para cada número entero. Luego, en una cáscara:

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

Sin golf

(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))))

Explicaciones

  • La función toma un número entero Nentre 1 y 3999 y un nombre de archivo

  • Yo uso (format nil "~@R" N)para convertir de decimal a romano. Por ejemplo:

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

    La ~@R cadena de control de formato se especifica para trabajar con enteros entre 1 y 3999. Es por eso que hay una limitación para el rango de entradas permitidas.

  • I itero sobre la cadena resultante para construir una lista que Pcontenga (radius width)parejas, para cada número C.

    • El ancho es un mapeo lineal simple: uso la cadena constante "IVXLCDM" para calcular la posición de C en él. Multiplicando por dos y sumando uno, obtenemos el valor deseado:

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

      Sin embargo, esto se hace de manera ligeramente diferente en la versión de golf:

             (position c " I V X L C D M")
      
    • El cálculo de cada radio tiene en cuenta el ancho de cada anillo, así como los espacios vacíos entre los anillos. Sin ninguna optimización de velocidad, los cálculos siguen siendo precisos porque no se basan en flotantes, sino en números racionales.

      Editar : cambié los parámetros para cumplir con las reglas de relleno.

  • Una vez hecho esto, sé el tamaño requerido del lienzo resultante (dos veces el último radio calculado).

  • Finalmente, dibujo un círculo para cada elemento Py guardo el lienzo.
volcado de memoria
fuente
1
"Este código admite todos los números romanos (IVXLCDM)". ¿Eso significa que su programa toma números romanos como entrada? Eso no es lo que pretendía, pero es genial. Accesorios para la animación también.
Rip Leeb
1
No, no, lo siento si esto no está claro: funciona para cualquier número entero entre 1 y 3999. En su pregunta, solo requirió entradas del 1 al 100, y su tabla no menciona D o M ... Lo editaré parte.
coredump
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}

Violín

TwiNight
fuente
¿Sin fragmento de pila?
Optimizador
@Optimizer Olvidé por completo que tenemos eso ahora
TwiNight
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);}}

Ejemplos

15

15

84

84

93

93

Formateado muy bien:

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
fuente
Por favor, publique algunos resultados. Perdón por no preguntar, este es el primer lugar.
Rip Leeb
3

Mathematica 9-301 249 bytes

: D Se siente engañoso usar la conversión incorporada a números romanos, pero bueno.

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}])

(Cuando hice esto anoche, no tuve mucho tiempo, pero me di cuenta de que podía jugar golf mucho más. Y también tomé algunas pistas de David Zhang ...: D ¡Gracias!)

Un poco más claro:

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}]
    )

Esta es una función que puede llamar así:

r[144]

ingrese la descripción de la imagen aquí

O bien, puede mostrar los resultados de los valores de una a b con:Table[r[i],{i,a,b}]

Nota : Esto solo funciona para valores de hasta 399.

kukac67
fuente
1

Pitón 2, 322 296

La secuencia de comandos lee el número que se convertirá desde stdin y muestra la imagen como marcado SVG.

.. Uso 'rojo' en lugar de 'negro', porque ahorra 2 caracteres :)

Aquí hay algunos ejemplos: para 23: http://jsfiddle.net/39xmpq49/ para 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
fuente
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);
}

martillo de lobo
fuente