Texto en un círculo

19

Escriba un programa o función que imprima una cadena de entrada alrededor del círculo discreto que tenga el radio mínimo posible. Por ejemplo, para la entrada This is an example, su programa debería generar:

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

Generación circular

Deberá utilizar el algoritmo de círculo de punto medio para calcular las coordenadas de cada punto del círculo discreto. Puede encontrar ejemplos sobre cómo implementar este algoritmo en esta página de Wikipedia .

Aquí está el pseudocódigo del algoritmo (basado en el ejemplo C de 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

Puede usar un algoritmo diferente si y solo si produce exactamente los mismos círculos que produce el algoritmo de círculo de punto medio, para todos los radios .

El círculo debe tener el radio más pequeño posible que aún permita escribir todas las letras de la entrada.

Si el círculo termina con más puntos que el número de caracteres en la cadena, los últimos caracteres de relleno serán espacios .

El primer carácter de la entrada debe imprimirse en el punto con coordenadas (Radius,0). Los caracteres posteriores se imprimen en sentido antihorario.

Entradas

La entrada es una cadena de cualquier carácter ASCII entre el espacio (32) y la tilde ~(126).

Puede suponer que la entrada siempre será válida, con menos de 256 caracteres y al menos 5 caracteres de longitud.

La entrada puede tomarse de STDIN, o como un parámetro de función, o algo similar.

Salidas

Puede enviar el resultado a STDOUT o devolverlo como una cadena desde una función.

Puede tener espacios finales, siempre que no haga que la línea exceda la línea más larga (la del medio) (como tal, la línea central no puede tener espacios finales).

Se permite una nueva línea final.

Casos de prueba

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            

Puntuación

Este es el , por lo que gana la respuesta más corta en bytes.

Fatalizar
fuente

Respuestas:

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

Sin golf:

(
  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
fuente
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;}}}}}

Prueba aquí

Estoy seguro de que se puede jugar mucho más, pero me está empezando a dar dolor de cabeza.

C, 324 bytes

Código más pequeño pero los resultados no son los mismos que los 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
fuente
3
Puede soltar void5 bytes y declarar algunos de los enteros en el alcance global para algunos bytes más, ya que se asume que las variables en el alcance global sin un tipo se intinicializan automáticamente 0.
Mego
1
Parece que realizó una edición anónima mientras estaba desconectado. Seguí adelante y lo aprobé, pero en general debes iniciar sesión para hacer tus ediciones. ;)
Alex A.
1

C, 494 bytes

Este usa el algoritmo real del círculo del punto medio:

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 golf:

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
fuente