Visualize o teorema de Nicômaco

35

O Teorema de Nichomachus relaciona o quadrado de uma soma à soma de cubos:

Teorema de Nichomachus

e tem uma bela visualização geométrica:

Visualização

Desafio: Crie a 2ª parte desta visualização em ascii.

Você precisará garantir que todas as demarcações visuais sejam mantidas pelo seu diagrama. Isso é mais simples com quatro "cores", embora seja possível obter com apenas três (veja o último exemplo abaixo para saber como). Com quatro cores, você usa duas para distinguir entre regiões em uma "faixa" (ou seja, as diferentes partes que compõem um único cubo) e duas para distinguir entre faixas adjacentes. Você também pode usar mais de quatro cores, se quiser. Se algo disso for confuso, o exemplo de saída abaixo deve esclarecer.

Entrada / Saída

A entrada é um número inteiro único maior que 0. A saída é uma grade ascii semelhante aos exemplos abaixo, correspondente à grade nivelada para esse número de entrada na imagem acima. Os espaços em branco à esquerda e à direita estão ok.

Este é o código de golfe, com regras padrão.

Saídas de amostra

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#####
+++++#####+++++
+++++#####+++++
+++++#####+++++
+++++#####+++++
+++++#####+++++

Versão de três cores para N = 4, graças a @BruceForte:

#oo+++oooo
o##+++oooo
o##+++####
+++ooo####
+++ooo####
+++ooo####
oo####++++
oo####++++
oo####++++
oo####++++
Jonah
fonte
6
Teorema das quatro cores: D
Freira gotejante
11
Você pode adicionar a saída para N = 5, por favor?
Uriel
11
@Uriel Done. Veja minha edição.
Jonah
Obrigado! Além disso, posso mudar o @ e os apenas na faixa externa em N = 4? Ou a saída deve ser uma substituição estrita desses textos por outro conjunto de caracteres?
Uriel
A comutação @Uriel está correta. Tudo o que importa é que as cores adjacentes não entrem em conflito, para que o padrão seja visível.
Jonah

Respostas:

17

MATL , 30 28 27 bytes

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

Experimente online!

Recursos bônus:

  • Para 26 bytes , a seguinte versão modificada produz saída gráfica :

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

    Experimente no MATL Online!

  • A imagem está implorando por alguma cor e custa apenas 7 bytes:

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

    Experimente no MATL Online!

  • Ou use uma versão mais longa (37 bytes) para ver como a matriz de caracteres é construída gradualmente :

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

    Experimente no MATL Online!

Saídas de exemplo

Para entrada 8, o seguinte mostra a versão básica, saída gráfica e saída gráfica em cores.

insira a descrição da imagem aqui

insira a descrição da imagem aqui

insira a descrição da imagem aqui

Explicação

Procedimento geral

Uma matriz numérica é construída das camadas externa para interna em Netapas, onde Nestá a entrada. Cada etapa substitui uma parte interna (superior esquerda) da matriz anterior. No final, os números na matriz obtida são alterados para caracteres.

Exemplo

Para entrada, 4a primeira matriz é

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 um segundo passo, a 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

é sobrescrito na metade superior do último. Então o mesmo é feito com

6 5 5
5 4 4
5 4 4

e finalmente com

3

A matriz resultante é

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 fim, 30é adicionado a cada entrada e os números resultantes são interpretados como pontos de código e convertidos em caracteres (começando em 33, correspondendo a !).

Construção das matrizes intermediárias

Para entrada N, considere diminuir valores de kde Npara 1. Para cada kum, é gerado um vetor de números inteiros de 1a k*(k+1)e, em seguida, cada entrada é dividida ke arredondada. Como exemplo, para k=4isso é fornecido (todos os blocos têm tamanho, kexceto o último):

1 1 1 1 2 2 2 2 3 3

enquanto que para k=3o resultado seria (todos os blocos têm tamanho k):

1 1 1 2 2 2

Esse vetor é adicionado, elemento a elemento com transmissão, a uma cópia transposta de si mesma; e depois ké adicionado a cada entrada. Para k=4isso dá

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

Essa é uma das matrizes intermediárias mostradas acima, exceto que é invertida horizontal e verticalmente. Então, tudo o que resta é inverter essa matriz e escrevê-la no canto superior esquerdo da matriz "acumulada" até agora, inicializada em uma matriz vazia para a primeira k=Netapa ( ).

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
fonte
Eu não conheço o MATL, mas você poderia salvar alguns bytes usando o mod10 em vez de adicionar 30 e converter em caracteres?
user2390246
Ou mesmo mod4 ...
user2390246
@ user2390246 Deseja mantê-los como números com um único dígito e evitar a conversão para char? Isso não funcionaria, porque a matriz numérica seria impressa com espaços entre os números. Mas, graças à idéia de qualquer maneira :-)
Luis Mendo
Justo. O que acontece com n> 226? Isso não vai além do intervalo de caracteres válidos? (Sem surpresa, expira na TIO, então eu não poderia verificar)
user2390246
@ user2390246 Sim, para números de entrada altos, ele sai para fora. E se considerarmos os caracteres ASCII, o ponto de código máximo é 127, e sai mais cedo. Mas como você notou, a memória fica sem memória antes que isso aconteça (a matriz de caracteres resultante é muito grande). De qualquer forma, trabalhando até um determinado tamanho de entrada apenas devido à memória ou dados limitações tipo é geralmente permitido
Luis Mendo
7

Python 2 , 187 178 164 162 152 152 bytes

-8 bytes graças a Mr.Xcoder
-1 byte graças a Stephen
-10 bytes graças 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]

Experimente online!

Cajado
fonte
Para quando você chegar em casa, 179 bytes .
Mr. Xcoder
@ Mr.Xcoder 178 bytes
Stephen
11
É permitido não incluir a contagem de bytes do nome da sua função lambda quando você a estiver usando recursivamente, ou seja, usando o nome no restante do código?
Jonathan Frech
sum(range(y))%y->y*~-y/2%y
Jonathan Frech 20/09
@ JonathanFrech sim, quando é recursivo, deve estar lá.
Rod
7

Carvão , 50 46 bytes

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

Experimente online! Link é a versão detalhada do código. Versão anterior de 50 bytes com explicação: Experimente online!

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: Eu faço um loop sobre o caractere em vez de tentar atribuí-lo diretamente, lporque você não pode atribuir diretamente o resultado da indexação de uma string a uma variável, pois é uma construção ambígua no Charcoal. Felizmente, a contagem de bytes é a mesma.

Neil
fonte
Tecnicamente, você pode, com uma variável de ASCII desde a sua ordem argumento é invertida (note que ele precisa de um operador para acesso por isso ainda menos é golfy)
ASCII-only
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;}

Experimente online!

Usa apenas três cores.

Conceitualmente, trabalha em uma grade girada em 180 graus:

000111
000111
000111
111220
111220
111001

E calcula as cores de acordo com a 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
fonte
11
123 bytes.
Jonathan Frech
@JonathanFrech Isso não é válido C e rompe com gcc -O2.
Nwellnhof 20/09/2017
Justo; é possível que o segundo código funcione apenas para três cores devido ao módulo three ( g(i%m,i/m,n)%3)?
Jonathan Frech
Sugerir em x/k&&y/kvez dex>=k&y>=k
roofcat 19/06/19
2

R , 131 126 123 bytes

3 bytes salvos graças 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,,"")}

Experimente online!

Ele usa o mesmo algoritmo da resposta MATL do @LuisMendo . A única diferença é que, em vez de converter em caracteres, a matriz é emitida com todos os valores mod4 para garantir que cada elemento seja um único caractere ASCII.

user2390246
fonte
11
123 bytes! Trouxe o forde volta para ciclo -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)

Experimente online!

TFeld
fonte
Se você definir J="".join;(+10 bytes) e substituir os dois "".joins (-2 * 7 = -14 bytes) por J(+2 bytes), poderá salvar um byte (pois deve haver um espaço adicional após o print; +1 byte) .
22817 Jonathan Frech