Visualiza el teorema de Nicómaco

35

El teorema de Nichomachus relaciona el cuadrado de una suma con la suma de cubos:

Teorema de Nicómaco

y tiene una hermosa visualización geométrica:

Visualización

Desafío: cree la 2ª parte de esta visualización en ascii.

Deberá asegurarse de que su diagrama confirme todas las demarcaciones visuales. Esto es más simple de hacer con cuatro "colores", aunque es posible lograrlo con solo tres (vea el último ejemplo a continuación para saber cómo). Con cuatro colores, utiliza dos para distinguir entre regiones dentro de una "tira" (es decir, las diferentes partes que forman un solo cubo), y dos para distinguir entre tiras adyacentes. También puede usar más de cuatro colores si lo desea. Si algo de esto es confuso, el resultado de ejemplo a continuación debería aclararse.

De entrada y salida

La entrada es un entero entero mayor que 0. La salida es una cuadrícula ascii similar a los ejemplos a continuación, que corresponde a la cuadrícula aplanada para ese número de entrada en la imagen de arriba. Los espacios en blanco iniciales y finales están bien.

Este es el código de golf, con reglas estándar.

Resultados de muestra

N = 1

#

N = 2

#oo   
o@@   
o@@   

N = 3

#oo+++
o@@+++
o@@+++
+++###
+++###
+++###

N = 4

#oo+++oooo
o@@+++oooo
o@@+++@@@@
+++###@@@@
+++###@@@@
+++###@@@@
oo@@@@oooo
oo@@@@oooo
oo@@@@oooo
oo@@@@oooo

N = 5

#oo+++oooo+++++
o@@+++oooo+++++
o@@+++@@@@+++++
+++###@@@@+++++
+++###@@@@+++++
+++###@@@@#####
oo@@@@oooo#####
oo@@@@oooo#####
oo@@@@oooo#####
oo@@@@oooo#####
+++++#####+++++
+++++#####+++++
+++++#####+++++
+++++#####+++++
+++++#####+++++

Versión tricolor para N = 4, gracias a @BruceForte:

#oo+++oooo
o##+++oooo
o##+++####
+++ooo####
+++ooo####
+++ooo####
oo####++++
oo####++++
oo####++++
oo####++++
Jonás
fuente
66
Teorema de cuatro colores: D
Leaky Nun
1
¿Puedes agregar la salida para N = 5 por favor?
Uriel
1
@Uriel Listo. Mira mi edición.
Jonás
¡Gracias! Además, ¿puedo cambiar @ y os solo en la tira exterior en N = 4? ¿O la salida debe ser una sustitución estricta de estos textos con otro juego de caracteres?
Uriel
El cambio de @Uriel está bien. Lo único que importa es que los colores adyacentes no entren en conflicto, de modo que el patrón sea visible.
Jonás

Respuestas:

17

MATL , 30 28 27 bytes

t:P"@:s:@/Xk&+@+8MPt&(]30+c

Pruébalo en línea!

Caracteristicas adicionales:

  • Para 26 bytes , la siguiente versión modificada produce una salida gráfica :

    t:P"@:s:@/Xk&+@+8MPt&(]1YG
    

    ¡Pruébalo en MATL Online!

  • La imagen está pidiendo algo de color , y solo cuesta 7 bytes:

    t:P"@:s:@/Xk&+@+8MPt&(]1YG59Y02ZG
    

    ¡Pruébalo en MATL Online!

  • O use una versión más larga (37 bytes) para ver cómo se construye gradualmente la matriz de caracteres :

    t:P"@:s:@/Xk&+@+8MPt&(t30+cD9&Xx]30+c
    

    ¡Pruébalo en MATL Online!

Salidas de ejemplo

Para la entrada es 8, lo siguiente muestra la versión básica, la salida gráfica y la salida gráfica en color.

ingrese la descripción de la imagen aquí

ingrese la descripción de la imagen aquí

ingrese la descripción de la imagen aquí

Explicación

Procedimiento general

Se construye una matriz numérica desde las capas externas a las internas en Npasos, donde Nestá la entrada. Cada paso sobrescribe una parte interna (superior izquierda) de la matriz anterior. Al final, los números en la matriz obtenida se cambian a caracteres.

Ejemplo

Para la entrada, 4la primera matriz es

10 10  9  9  9  9  8  8  8  8
10 10  9  9  9  9  8  8  8  8
 9  9  8  8  8  8  7  7  7  7
 9  9  8  8  8  8  7  7  7  7
 9  9  8  8  8  8  7  7  7  7
 9  9  8  8  8  8  7  7  7  7
 8  8  7  7  7  7  6  6  6  6
 8  8  7  7  7  7  6  6  6  6
 8  8  7  7  7  7  6  6  6  6
 8  8  7  7  7  7  6  6  6  6

Como segundo paso, la matriz

7 7 7 6 6 6
7 7 7 6 6 6
7 7 7 6 6 6
6 6 6 5 5 5
6 6 6 5 5 5
6 6 6 5 5 5

se sobrescribe en la mitad superior de este último. Entonces lo mismo se hace con

6 5 5
5 4 4
5 4 4

y finalmente con

3

La matriz resultante es

3 5 5 6 6 6 8 8 8 8
5 4 4 6 6 6 8 8 8 8
5 4 4 6 6 6 7 7 7 7
6 6 6 5 5 5 7 7 7 7
6 6 6 5 5 5 7 7 7 7
6 6 6 5 5 5 7 7 7 7
8 8 7 7 7 7 6 6 6 6
8 8 7 7 7 7 6 6 6 6
8 8 7 7 7 7 6 6 6 6
8 8 7 7 7 7 6 6 6 6

Por último, 30se agrega a cada entrada y los números resultantes se interpretan como puntos de código y se convierten en caracteres (comenzando en 33, correspondiente a !).

Construcción de las matrices intermedias.

Para la entrada N, considere disminuir los valores de kdesde Na 1. Para cada uno k, se genera un vector de enteros de 1a k*(k+1), y luego cada entrada se divide ky se redondea. Como ejemplo, para k=4esto da (todos los bloques tienen tamaño kexcepto el último):

1 1 1 1 2 2 2 2 3 3

mientras que para k=3el resultado sería (todos los bloques tienen tamaño k):

1 1 1 2 2 2

Este vector se agrega, en cuanto a elementos con difusión, a una copia transpuesta de sí mismo; y luego kse agrega a cada entrada. Para k=4esto da

6  6  6  6  7  7  7  7  8  8
6  6  6  6  7  7  7  7  8  8
6  6  6  6  7  7  7  7  8  8
6  6  6  6  7  7  7  7  8  8
7  7  7  7  8  8  8  8  9  9
7  7  7  7  8  8  8  8  9  9
7  7  7  7  8  8  8  8  9  9
7  7  7  7  8  8  8  8  9  9
8  8  8  8  9  9  9  9 10 10
8  8  8  8  9  9  9  9 10 10

Esta es una de las matrices intermedias que se muestran arriba, excepto que se voltea horizontal y verticalmente. Entonces, todo lo que queda es voltear esta matriz y escribirla en la esquina superior izquierda de la matriz "acumulada" hasta ahora, inicializada en una matriz vacía para el primer ( k=N) paso.

Código

t       % Implicitly input N. Duplicate. The first copy of N serves as the
        % initial state of the "accumulated" matrix (size 1×1). This will be 
        % extended to size N*(N+1)/2 × N*(N+1)/2 in the first iteration
 :P     % Range and flip: generates vector [N, N-1, ..., 1]
"       % For each k in that vector
  @:    %   Push vector [1, 2, ..., k]
  s     %   Sum of this vector. This gives 1+2+···+k = k*(k+1)/2
  :     %   Range: gives vector [1, 2, ..., k*(k+1)/2]
  @/    %   Divide each entry by k
  Xk    %   Round up
  &+    %   Add vector to itself transposed, element-wise with broadcast. Gives
        %   a square matrix of size k*(k+1)/2 × k*(k+1)/2
  @+    %   Add k to each entry of the this matrix. This is the flipped
        %   intermediate matrix
  8M    %   Push vector [1, 2, ..., k*(k+1)/2] again
  Pt    %   Flip and duplicate. The two resulting, equal vectors are the row and
        %   column indices where the generated matrix will be written. Note that
        %   flipping the indices has the same effect as flipping the matrix
        %   horizontally and vertically (but it's shorter)
  &(    %   Write the (flipped) intermediate matrix into the upper-left
        %   corner of the accumulated matrix, as given by the two (flipped)
        %   index vectors 
]       % End
30+     % Add 30 to each entry of the final accumulated matrix
c       % Convert to char. Implicitly display
Luis Mendo
fuente
No conozco MATL en absoluto, pero ¿podría guardar los bytes tomando mod10 en lugar de agregar 30 y convertir a carácter?
user2390246
O incluso mod4 ...
user2390246
@ user2390246 ¿Quiere mantenerlos como números con un solo dígito y evitar la conversión a caracteres? Eso no funcionaría, porque la matriz numérica se imprimiría con espacios entre los números. Pero gracias por la idea de todos modos :-)
Luis Mendo
Lo suficientemente justo. ¿Qué pasa con n> 226? ¿No saldrá eso del rango de caracteres válidos? (Como era de esperar, se agota el tiempo de espera en TIO, por lo que no pude comprobar)
user2390246
@ user2390246 Sí, para números de entrada altos sale al exterior. Y si consideramos los caracteres ASCII, el punto de código máximo es 127, por lo que sale afuera incluso antes. Pero como notó, se queda sin memoria antes de que eso suceda (la matriz de caracteres resultante es demasiado grande). De todos modos, generalmente se permite trabajar hasta un tamaño de entrada dado debido a limitaciones de memoria o tipo de datos
Luis Mendo
7

Python 2 , 187 178 164 162 152 bytes

-8 bytes gracias a Mr.Xcoder
-1 byte gracias a Stephen
-10 bytes gracias a Jonathan Frech

g=lambda y:y>1and[l+y*f(y,i)for i,l in enumerate(g(y-1))]+y*[''.join(f(y,i)for i in range(y*-~y/2))]or['#']
f=lambda y,i:'0@+#'[(y*~-y/2%y+i)/y%2+y%2*2]

Pruébalo en línea!

Barra
fuente
Para cuando llegues a casa, 179 bytes .
Sr. Xcoder
@ Mr.Xcoder 178 bytes
Stephen
1
¿Está permitido no incluir el recuento de bytes de nombre de la función lambda cuando lo está usando de forma recursiva, es decir, usando su nombre en el resto del código?
Jonathan Frech
sum(range(y))%y->y*~-y/2%y
Jonathan Frech
@ JonathanFrech, sí, cuando es recursivo debe estar allí.
Rod
7

Carbón , 50 46 bytes

F⮌…·¹N«≔⊘×ι⊕ιθF⊕⊘ι«F§#+@⁺ικ«UO⁻θ×ικθλUOθ⁻θ×ικλ

Pruébalo en línea! El enlace es a la versión detallada del código. Versión anterior de 50 bytes con explicación: ¡ Pruébelo en línea!

F⮌…·¹N«≔÷×ι⁺¹ι²θF⁺¹÷鲫F§#+@⁺ικ«UO⁻θ×ικθλUOθ⁻θ×ικλ

F     «     Loop over
  …·¹       Inclusive range from 1 to
     N      Input as a number
 ⮌          Reversed

   ι⁺¹        Add 1 to current index
  ×   ι       Multiply by current index
 ÷     ²      Divide by 2
≔       θ     Assign to q

F     «      Loop over
             Implicit range from 0 to
   ÷ι²       Half the current index
 ⁺¹          Plus 1

F       «    Loop over
  #+@        Literal string
 §           Circularly indexed by
     ⁺ικ     Sum of outer and inner index

    ×ικ     Multiply outer and inner index
  ⁻θ        Subtract from q
UO     θλ   Draw an oblong (q-ik, q) using that character

UOθ⁻θ×ικλ   Draw an oblong (q, q-ik) using that character

Nota: hago un bucle sobre el carácter en lugar de tratar de asignarle el carácter directamente lporque no se puede asignar directamente el resultado de indexar una cadena a una variable, ya que es una construcción ambigua en Charcoal. Afortunadamente, el recuento de bytes es el mismo.

Neil
fuente
Técnicamente puede hacerlo, con una variable ASCII ya que su orden de argumentos está invertido (tenga en cuenta que necesita un operador para acceder, por lo que todavía es menos golfoso)
solo ASCII el
5

C (gcc) , 135 128 120 bytes

f(n,m,i,x,y,k){for(m=n*-~n/2,i=m*m;i--;printf("\n%d"+!!(~i%m),(x/k+y/k+k)%3))for(x=i%m,y=i/m,k=n;x>=k&y>=k;x-=k--)y-=k;}

Pruébalo en línea!

Utiliza solo tres colores.

Conceptualmente, funciona en una cuadrícula girada 180 grados:

000111
000111
000111
111220
111220
111001

Y calcula los colores de acuerdo con la fórmula:

c(x,y,n) = c(x-n,y-n,n-1)                   if x >= n and y >= n
         = (x div n + y div n + n) mod 3    otherwise
nwellnhof
fuente
1
123 bytes.
Jonathan Frech
@ JonathanFrech Esto no es válido C y rompe con gcc -O2.
nwellnhof
Lo suficientemente justo; ¿Es posible que el segundo código solo funcione para tres colores debido al módulo three ( g(i%m,i/m,n)%3)?
Jonathan Frech
Sugerir en x/k&&y/klugar dex>=k&y>=k
ceilingcat
2

R , 131 126 123 bytes

3 bytes guardados gracias a @Giuseppe

function(n){l=w=sum(1:n)
m=matrix(,l,l)
for(i in n:1){m[l:1,l:1]=outer(x<-(1:l-1)%/%i,x,`+`)+i
l=l-i}
write(m%%4,"",w,,"")}

Pruébalo en línea!

Este sistema utiliza el mismo algoritmo que @LuisMendo 's respuesta MAT . La única diferencia es que, en lugar de convertir a caracteres, la matriz se genera con todos los valores mod4 para garantizar que cada elemento sea un único carácter ascii.

usuario2390246
fuente
1
123 bytes! Recuperé el forbucle para -1 byte :)
Giuseppe
1

Python 2 , 176 175 bytes

n=input()
R,J=range,''.join;r=[]
for i in R(n+1):
 S=sum(R(i));c='AxBo'[i%2::2]
 for j in R(S):r[~j]+=c[j/i%2]*i
 r+=[J(c[-j/i%2]for j in R(S+i,0,-1))]*i
for l in r:print J(l)

Pruébalo en línea!

TFeld
fuente
Si define J="".join;(+10 bytes) y reemplaza ambos "".joins (-2 * 7 = -14 bytes) con J(+2 bytes), puede guardar un byte (ya que debe haber un espacio adicional después del print; +1 byte) .
Jonathan Frech