Números como gráficos circulares

36

Primeiro, estude esse quebra - cabeça para ter uma ideia do que você estará produzindo.

Seu desafio é escrever um programa ou função que produza um gráfico circular como os do quebra-cabeça, considerando um número (base 10) entre 1 e 100 (inclusive). Isso é semelhante a esse desafio , exceto que você produzirá um gráfico em vez de algarismos romanos. Os seguintes círculos representam os números de 1 a 10, da esquerda para a direita:

padrão de círculo

Como diz a resposta do quebra-cabeça, seu gráfico deve ler-se como um número romano de dentro para fora, onde a espessura da linha representa os símbolos dos números romanos e o gráfico inteiro representa o número. Para sua referência, aqui estão as espessuras de linha que você precisará. Cada linha deve ter um preenchimento de 3px entre ela e a próxima.

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

Poste uma amostra ou duas da sua saída. Suponha que a entrada esteja correta, brechas padrão , etc. e assim por diante. Isso é código de golfe, e o menor número de bytes vence. Em caso de empate, a maioria dos votos vence. Boa sorte!

Rip Leeb
fonte
3
É necessário o tamanho absoluto correto da imagem ou é suficiente ter os tamanhos relativos corretos?
David Zhang
@DavidZhang Sim, por favor, atenha-se aos tamanhos de linha e preenchimento listados, por uma questão de justiça.
Rip Leeb

Respostas:

15

Mathematica - 166 181 bytes

Um pouco mais conciso do que a outra resposta do Mathematica, graças em parte a um estilo sem pontos.

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 o espaço em branco é apenas para clareza. Isso define uma função anônima que retorna o gráfico desejado.

Animação

Círculos animados

A geração de um GIF animado dos círculos numéricos é trivial no Mathematica, que possui funções internas para animar e exportar seqüências de objetos arbitrários. Assumindo que o código acima acabou de ser executado,

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

Saída de exemplo

Saída de exemplo

David Zhang
fonte
Poste alguns resultados. Desculpe por não perguntar, este é o primeiro lugar. Eu também mudei a pergunta para aceitar funções.
Rip Leeb
Obrigado pelas sugestões @ MartinBüttner. O código foi corrigido para gerar imagens com o tamanho correto e a saída de exemplo foi adicionada.
David Zhang
3
Sua animação mexe. Não que eu pudesse fazer melhor.
corsiKa
Hmm, você está certo. Realmente não sei por que isso acontece, considerando que especifiquei explicitamente o intervalo de plotagem para o Mathematica.
David Zhang
Talvez relacionado com a abanar: mathematica.stackexchange.com/q/134272
coredump
15

Lisp comum - 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)))

Exemplos

insira a descrição da imagem aqui(1) insira a descrição da imagem aqui(24)

insira a descrição da imagem aqui(104) insira a descrição da imagem aqui(1903) insira a descrição da imagem aqui(3999)

Animação

Para números de 1 a 400:

Novo

NB: Para o registro, esta animação é feita da seguinte maneira:

Eu tenho uma versão modificada do código, nomeada ringsque retorna a largura da imagem produzida. Portanto, o resultado do seguinte loop é o tamanho máximo, aqui 182 :

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

O loop inteiro leva 9,573 segundos. Isso fornece aproximadamente 24ms para cada número inteiro. Então, em uma concha:

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

Explicações

  • A função assume um número inteiro Nentre 1 e 3999 e um nome de arquivo

  • Eu uso (format nil "~@R" N)para converter de decimal para romano. Por exemplo:

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

    A ~@R cadeia de controle de formato é especificada para funcionar com números inteiros entre 1 e 3999. É por isso que há uma limitação para o intervalo de entradas permitidas.

  • Eu itero sobre a string resultante para criar uma lista Pcontendo (radius width)casais, para cada numeral C.

    • A largura é um mapeamento linear simples: eu uso a cadeia constante "IVXLCDM" para calcular a posição de C nela. Multiplicando por dois e adicionando um, obtemos o valor desejado:

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

      No entanto, isso é feito de maneira ligeiramente diferente na versão golfed:

             (position c " I V X L C D M")
      
    • O cálculo de cada raio leva em consideração a largura de cada anel, bem como os espaços vazios entre os anéis. Sem qualquer otimização de velocidade, os cálculos permanecem precisos porque não são baseados em flutuadores, mas em números racionais.

      Editar : alterei os parâmetros para cumprir as regras de preenchimento.

  • Feito isso, conheço o tamanho necessário da tela resultante (duas vezes o raio computado mais recente).

  • Por fim, desenhei um círculo para cada elemento Pe salve a tela.
coredump
fonte
1
"Este código suporta todos os números romanos (IVXLCDM)". Isso significa que o seu programa usa números romanos como entrada? Não era isso que eu pretendia, mas bem legal. Suportes para a animação também.
Rip Leeb
1
Não, não, desculpe se isso não está claro: ele funciona para qualquer número inteiro entre 1 e 3999. Na sua pergunta, você só solicitou entradas de 1 a 100 e sua tabela não menciona D ou M ... parte.
Coredump26
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}

Violino

TwiNight
fonte
Nenhum snippet de pilha?
Optimizer
@Optimizer Esqueci completamente o que temos agora
TwiNight 26/11/14
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);}}

Exemplos

15

15

84

84

93

93

Formatado bem:

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
fonte
Poste alguns resultados. Desculpe por não perguntar, este é o primeiro lugar.
Rip Leeb
3

Mathematica 9 - 301 249 bytes

: D Parece barato usar a conversão incorporada para números romanos, mas ei.

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

(Quando eu fiz isso ontem à noite, não tive muito tempo, mas percebi que poderia ser muito melhor. E também peguei algumas dicas de David Zhang ...: D Obrigado!)

Um pouco mais claramente:

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 é uma função que você pode chamar assim:

r[144]

insira a descrição da imagem aqui

Ou, você pode mostrar os resultados de valores de um a b com:Table[r[i],{i,a,b}]

Nota : Isso funciona apenas para valores de até 399.

kukac67
fonte
1

Python 2, 322 296

O script lê o número a ser convertido do stdin e gera a imagem como marcação SVG.

.. Eu uso 'vermelho' em vez de 'preto', porque economiza 2 caracteres :)

Aqui estão alguns exemplos: 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
fonte
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);
}

martelo de lobo
fonte