Texto em um círculo

19

Escreva um programa ou função que imprima uma sequência de entrada em torno do círculo discreto que tenha o raio mínimo possível. Por exemplo, para entrada This is an example, seu programa deve gerar:

  a si   
 n     s 
        i
e       h
x       T
a        
m        
 p       
  le     

Geração de círculo

Você deve usar o algoritmo do círculo do ponto médio para calcular as coordenadas de cada ponto do círculo discreto. Você pode encontrar exemplos de como implementar esse algoritmo nesta página da Wikipedia .

Aqui está o pseudo-código do algoritmo (com base no exemplo C da Wikipedia):

integer x = radius
integer y = 0
int decisionCriterion = 1 - x

while y <= x 
    point at coordinates (x,y) belongs to the circle   // Octant 1
    point at coordinates (y,x) belongs to the circle   // Octant 2
    point at coordinates (-x,y) belongs to the circle  // Octant 4
    point at coordinates (-y,x) belongs to the circle  // Octant 3
    point at coordinates (-x,-y) belongs to the circle // Octant 5
    point at coordinates (-y,-x) belongs to the circle // Octant 6
    point at coordinates (x,-y) belongs to the circle  // Octant 7
    point at coordinates (y,-x) belongs to the circle  // Octant 8

    y++
    if decisionCriterion <= 0
        decisionCriterion += 2 * y + 1
    else
        x--
        decisionCriterion += 2 * (y - x) + 1
end while

Você pode usar um algoritmo diferente se, e somente se, produzir exatamente os mesmos círculos que o algoritmo do círculo do ponto médio produz, para todos os raios .

O círculo deve ter o menor raio possível que ainda permita escrever todas as letras da entrada.

Se o círculo terminar com mais pontos que o número de caracteres na sequência, os últimos caracteres de preenchimento serão espaços .

O primeiro caractere da entrada deve ser impresso no ponto com coordenadas (Radius,0). Os caracteres subsequentes são impressos no sentido anti-horário.

Entradas

A entrada é uma sequência de caracteres ASCII entre o espaço (32) e o til ~(126).

Você pode assumir que a entrada sempre será válida, menor que 256 caracteres e pelo menos 5 caracteres.

A entrada pode ser obtida no STDIN, ou como um parâmetro de função, ou qualquer coisa semelhante.

Saídas

Você pode enviar o resultado para STDOUT ou retorná-lo como string de uma função.

Você pode ter espaços à direita, desde que ela não exceda a linha mais longa (a do meio) (como tal, a linha do meio não pode ter espaços à direita).

Uma nova linha à direita é permitida.

Casos de teste

Input: Hello, World!
Output:
  ,ol  
     l 
W     e
o     H
r      
 l     
  d!   


Input: 4 8 15 16 23 42
Output:
  51   
     8 
1      
6     4

 2   2 
  3 4  


Input: Programming Puzzles & Code golf
Output:
     gnim    
  uP     ma  
 z         r 
 z         g 
l           o
e           r
s           P

&            

 C           
  od     f   
    e Gol    


Input: Ash nazg durbatuluk, ash nazg gimbatul, ash nazg thrakatuluk agh burzum-ishi krimpatul.
Output:
            zan hsa ,           
           g         ku          
        ig             lu        
      bm                 ta      
     a                     b     
    t                       r    
   u                         u   
   l                         d   
  ,                              
                              g  
 a                             z 
 s                             a 
h                               n

n                               h
a                               s
z                               A
g                                

t                                
h                                
 r                               
 a                             . 
  k                           l  
  a                           u  
   t                         t   
   u                         a   
    l                       p    
     u                     m     
      k                  ri      
        ag              k        
          h          hi          
            burzum-is            

Pontuação

Isso é , então a resposta mais curta em bytes vence.

Fatalizar
fonte

Respostas:

1

Mathematica, 359 357 354

(L=Length;T=Tuples;c=Characters@#;For[r=1,L[p=RotateRight[SortBy[#,ArcTan@@N@#&]+r+1,L@#/4+1]&@(f=1-r;X=1;Y=-2r;x=0;y=r;q={{0,r},{0,-r},{r,0},{-r,0}};While[x<y,If[f>0,y--;f+=Y+=2];x++;f+=X+=2;q=Join[q,T@{{x,-x},{y,-y}},T@{{y,-y},{x,-x}}]];Union@q)]<L@c,r++];R=2r+1;s="";Do[s=s<>({u,v}/.Thread[p~Take~L@c->c]/.{_,_}->" ")<>If[v==R,"\n",""],{u,R},{v,R}];s)&

Ungolfed:

(
  L = Length;
  T = Tuples;
  c = Characters@#;
  For[r = 1,
   L[
     p = RotateRight[
         SortBy[#, ArcTan @@ N@# &] + r + 1, L@#/4 + 1
         ] &@(
        f = 1 - r;
        X = 1;
        Y = -2 r;
        x = 0;
        y = r;
        q = {{0, r}, {0, -r}, {r, 0}, {-r, 0}};
        While[x < y,
         If[f > 0,
          y--;
          f += Y += 2
          ];
         x++;
         f += X += 2;
         q = Join[q, T@{{x, -x}, {y, -y}}, T@{{y, -y}, {x, -x}}]
         ];
        Union@q
        )] < L@c,
   r++];
  R = 2 r + 1;
  s = "";
  Do[s = s <> ({u, v} /. Thread[p ~ Take ~ L@c -> c] /. {_, _} -> " ") <>
      If[v == R, "\n", ""],
   {u, R}, {v, R}];
  s
  ) &
shrx
fonte
3

C, 367 bytes

#include<math.h>
main(){char*m="12345678",b[9999];int p,i,n,q,c,l=strlen(m),r=1,d,f=0;float o,s;for(;!f;r++){f=0;q=r*r;c=r/4;o=6.3,s=o/99.;memset(b,0,q);for(i=0;i<l;i++){p=1;f=0;while(p&&o>0){d=(c-1+(int)(sin(o)*c))*r+c-1+(int)(cos(o)*c);f+=p=b[d];if(!p)b[d]=m[i];o-=s;}}if(f){for(n=p=0;n<q;n++){p+=c=b[n];putchar(c?c:32);if(n%r==r-1){if(!p)n=q;putchar(10);p=0;}}}}}

Teste aqui

Tenho certeza de que pode jogar golfe muito mais, mas está começando a me dar dor de cabeça.

C, 324 bytes

Código menor, mas os resultados não são os mesmos dos OP

#include<math.h>
main(){char*m="12345678",b[9999];int q,c,l=strlen(m),r=1,d,i=0;float o;for(;i<l;r++){i=0;c=r/2;q=r*r;memset(b,0,q);for(o=6.28;o>=0&&i<l;o-=0.001){d=(c-1+(int)(sin(o)*c))*r+c-1+(int)(cos(o)*c);if(!b[d]){b[d]=m[i++];}}}for(d=i=0,--r;d<q;d++){i+=c=b[d];putchar(c?c:32);if(d%r==r-1){putchar(10);d=i?d:q;i=0;}}}

       an hsa ,k
      gz       ulu
    ig           ta
   bm             br
  ta               ud
 lu                  g
 ,                   z
a                    an
s
h                     h
                      s
n                     A
a
z
g                     l
 t                   tu
 h                   a
 ra                 mp
  ka               ri
   tu              k
    lu           hi
     k a       -is
       gh burzum
Johan du Toit
fonte
3
Você pode descartar os void5 bytes e declarar alguns dos números inteiros no escopo global por mais alguns bytes, pois as variáveis ​​no escopo global sem um tipo são assumidas inte inicializadas automaticamente 0.
Mego
11
Parece que você fez uma edição anônima enquanto estava desconectado. Fui em frente e aprovei, mas em geral você deve fazer login para fazer suas edições. ;)
Alex A.
1

C, 494 bytes

Este usa o algoritmo real do círculo do ponto médio:

void main(){char s[]="12345678";int a[9999],b[9999],f=0,c,h,x,y,e,q,t,u,v,g,i,d,l,r=0,k=strlen(s);for(;f<k;r++){c=r;e=r*2+1;q=e*e;memset(b,0,q*4);f=0;l=0;for(i=0;i<8;i++){x=r;y=0;d=1-x;for(x=r,y=0,d=1-x;y<=x;y++,d+=2*d>0?y- --x:y+1){t=(i+1)%4>1;u=t?y:x;v=t?x:y;h=(c+v*(i>3?1:-1))*e+(c+u*(i>1&&i<6?-1:1));if(!b[h])b[h]=f<k?s[f]:0,a[f]=h,f++;}if(i%2){for(g=0;g<(f-l)/2;g++)t=b[a[l+g]],b[a[l+g]]=b[a[f-1-g]],b[a[f-1-g]]=t;}l=f;}}for(i=0;i<q;i++){c=b[i];putchar(c?c:32);if(i%e==e-1)putchar(10);}}

Código De-Golfed:

void main() {
    char text[]="Ash nazg durbatuluk, ash nazg gimbatul, ash nazg thrakatuluk agh burzum-ishi krimpatul.";

    char points[9999];
    int pos[9999];

    int sl = strlen(text);
    int r = 0;
    int pc = 0; // point count
    int lc = 0; // last count

    int c, h, x, y, e, q, t, u, v, g, i, d;

    // increase radius until number of points => strlen(text)
    for(; pc<sl; r++) {
        c = r;
        e = r * 2 + 1;
        q = e * e;
        memset(points,0,q);
        pc = 0;
        lc = 0;

        // loop through the octants
        for(i=0; i<8; i++) {

            // midpoint loop
            x = r;
            y = 0;
            d = 1 - x;
            while (y <= x) {

                // calc index of point
                t = (i + 1) % 4 > 1;
                u = t ? y : x;
                v = t ? x : y;
                h = (c + v * (i > 3 ? 1 : -1)) * e + (c + u * (i > 1 && i < 6 ? -1 : 1)); 

                // add point if space is empty
                if(!points[h]) { 
                    points[h] = pc < sl ? text[pc] : 0;
                    pos[pc] = h;
                    pc++;
                }

                y++;
                d += 2 * d > 0 ? y- --x : y + 1;
            }

            if(i % 2) {
                // reverse point order for odd octants
                for(g=0; g<(pc-lc)/2; g++)
                {
                    t = points[pos[lc + g]];
                    points[pos[lc + g]] = points[pos[pc - 1 - g]];
                    points[pos[pc - 1 - g]] = t;
                }
            }
            lc = pc;
        }
    }

    // write output
    for(i=0;i<q;i++)
    {
        c = points[i];
        putchar(c ? c : 32);
        if(i % e == e - 1)
            putchar(10);
    }
}
Johan du Toit
fonte