Visualize o maior divisor comum

28

fundo

O maior divisor comum ( gcd para abreviar) é uma função matemática conveniente, pois possui muitas propriedades úteis. Uma delas é a identidade de Bézout : se d = gcd(a, b), então existem inteiros xe ytal d = x*a + y*b. Nesse desafio, sua tarefa é visualizar essa propriedade com arte ASCII simples.

Entrada

Suas entradas são dois números inteiros positivos ae b, dados em qualquer formato razoável. Você também pode receber entradas unárias (repetições de um único caractere ASCII imprimível de sua escolha), mas deve ser consistente e usar o mesmo formato para ambas as entradas. As entradas podem estar em qualquer ordem e podem ser iguais.

Saída

Sua saída é uma sequência sde comprimento lcm(a, b) + 1( lcm significa o menor múltiplo comum). Os caracteres de srepresentam números inteiros de 0até lcm(a, b). O caractere s[i]é minúsculo ose ifor múltiplo de aou b, e um período .caso contrário. Observe que zero é um múltiplo de cada número. Agora, devido à identidade de Bézout, haverá pelo menos um par de caracteres ona sdistância exata gcd(a, b). O par mais à esquerda deve ser substituído por Os maiúsculo ; este é o resultado final.

Exemplo

Considere as entradas a = 4e b = 6. Então nós temos gcd(a, b) = 2e lcm(a, b) = 12, portanto, o comprimento de sserá 13. Os múltiplos de ae bsão destacados da seguinte forma:

0  1  2  3  4  5  6  7  8  9 10 11 12
o  .  .  .  o  .  o  .  o  .  .  .  o

Existem dois pares de os com a distância dois, mas substituiremos apenas os mais à esquerda por Os, então a saída final é

o...O.O.o...o

Regras e pontuação

Você pode escrever um programa completo ou uma função. A menor contagem de bytes vence e as brechas padrão não são permitidas.

Casos de teste

 1  1 -> OO
 2  2 -> O.O
 1  3 -> OOoo
 4  1 -> OOooo
 2  6 -> O.O.o.o
 2  3 -> o.OOo.o
10  2 -> O.O.o.o.o.o
 4  5 -> o...OO..o.o.o..oo...o
 8  6 -> o.....O.O...o...o.o.....o
12 15 -> o...........O..O........o.....o.....o........o..o...........o
19 15 -> o..............o...o..........o.......o......o...........o..o..............OO.............o....o.........o........o.....o............o.o..............o.o............o.....o........o.........o....o.............oo..............o..o...........o......o.......o..........o...o..............o
Zgarb
fonte
1
Ao receber informações unárias, podemos escolher qualquer caractere? (Em particular, que tal ., oou O.) Ou precisa ser 1? Ou 0?
Martin Ender
1
@ MartinBüttner Pode ser qualquer caractere, desde que você seja consistente e use o mesmo formato para as duas entradas.
Zgarb 01/01
2
Estou surpreso que você não tenha usado 3 e 5 como um dos seus casos de teste.
Neil
Posso usar o buildin?
Akangka 02/01
@ChristianIrwan Sim, todos os embutidos são permitidos.
Zgarb

Respostas:

7

Jolf, 52 bytes

on*'.wm9jJΡR m*Yhm8jJDN?<*%Sj%SJ1'o'.}"'o%o"n"O%O"n

Dividirei esse código em duas partes.

on*'.wm9jJ
on         set n
  *'.       to a dot repeated
      m9jJ  the gcd of two numeric inputs

ΡR m*Yhm8jJDN?<*%Sj%SJ1'o'.}"'o%o"n"O%O"n
    *Y                                    multiply (repeat) Y (Y = [])
      hm8jJ                                by the lcm of two inputs + 1
  _m       DN              }              and map the array of that length
             ?<*%Sj%SJ1'o'.               "choose o if i%a*(i%b)<1; otherwise choose ."
 R                          "'            join by empty string
Ρ                            'o%o"n        replace once (capital Rho, 2 bytes): "o"+n+"o"
                                   "O%O"n   with "O"+n+"O"
                                          implicit printing

Experimente aqui!

Conor O'Brien
fonte
Mais curto que tudo o mais até agora. : P
Rɪᴋᴇʀ
1
@RikerW Yes! Espero que Jolf finalmente vença, uma vez.
Conor O'Brien
10

Julia, 111 110 107 103 96 bytes

f(a,b)=replace(join([i%a*(i%b)<1?"o":"."for i=0:lcm(a,b)]),"o$(d="."^(gcd(a,b)-1))o","O$(d)O",1)

Esta é uma função que aceita dois números inteiros e retorna uma string.

Ungolfed:

function f(a::Int, b::Int)
    # Construct an array of dots and o's
    x = [i % a * (i % b) < 1 ? "o" : "." for i = 0:lcm(a, b)]

    # Join it into a string
    j = join(x)

    # Replace the first pair with distance gcd(a, b) - 1
    replace(j, "o$(d = "."^(gcd(a, b) - 1))o", "O$(d)O", 1) 
end

Guardou um byte graças a nimi!

Alex A.
fonte
10

Retina , 112 109 99 94 91 bytes

^
. 
+r`(?<!^\1+). (.+) 
$'$0
.(?=.* (.+) (.+))(?=\1* |\2* )
o
o(\.*)o((\1\.*o)*) .*
O$1O$2

Acho que não é muito competitivo, mas a teoria dos números na Retina é sempre bastante divertida. :)

Recebe a entrada como números unários usando .como dígito unário.

Experimente online.

Explicação

^
. 

Isso insere um .espaço na frente da entrada. Isso acabará se tornando o resultado.

+r`(?<!^\1+). (.+) 
$'$0

Isso antecede o LCM de ae bpara a sequência. Como já temos um .lá, acabaremos com lcm(a,b)+1. Isso é realizado anexando repetidamente b, desde aque não divida esse novo prefixo. Capturamos aem um grupo um e, em seguida, verificamos se conseguimos alcançar o início da string, correspondendo essa captura pelo menos uma vez. bé então inserido na string através do raramente usado, $'que insere tudo após a partida na substituição.

.(?=.* (.+) (.+))(?=\1* |\2* )
o

Este combina caracteres em posições divididas por aou b. Ele faz uso do fato de que o resultado é simétrico: já que lcm(a,b)é dividido por ambos ae bvai para a esquerda ao subtrair instâncias de aou bproduz o mesmo padrão que o direito de 0adicioná-las. O primeiro lookahead simplesmente captura ae b. O segundo lookahead verifica se há um múltiplo de cada um aou bcaracteres antes do primeiro espaço.

o(\.*)o((\1\.*o)*) .*
O$1O$2

Conforme declarado na Wikipedia, além da identidade de Bézout, também é verdade que

O maior divisor comum dé o menor número inteiro positivo que pode ser escrito como ax + by.

Isso implica que o GCD corresponderá ao menor intervalo entre dois os na saída. Portanto, não precisamos nos preocupar em encontrar o GCD. Em vez disso, apenas procuramos a primeira instância do menor intervalo. o(\.*)ocorresponde a uma lacuna candidata e captura sua largura no grupo 1. Em seguida, tentamos alcançar o primeiro espaço alternando entre uma referência anterior ao grupo 1 oes (com .s adicionais opcionais ). Se houver uma lacuna mais curta à direita, isso não corresponderá, porque não podemos superar essa lacuna com a referência anterior. Assim que todas as lacunas adicionais forem pelo menos tão amplas quanto a atual, isso corresponderá. Capturamos o final da string LCM no grupo 2 e combinamos o restante da string com .*. Escrevemos de volta as maiúsculasOs (com o intervalo entre elas) e o restante da sequência LCM, mas descarte tudo a partir do espaço, para remover ae bdo resultado final.

Martin Ender
fonte
Não sei muito sobre a teoria dos números da retina, mas não definiria o caractere de entrada para algo que não exija escape de salvar bytes? Ou seja (\.*)=>(a*)
Conor O'Brien
@ CᴏɴᴏʀO'Bʀɪᴇɴ Sim, mas depois precisaria substituí-lo por .mais tarde, que custa quatro bytes (e se livrar das fugas, apenas 3).
Martin Ender
Ohh Legal! Resposta muito interessante.
Conor O'Brien 01/01
5

, 50 caracteres / 90 bytes

⩥Мū⁽îí+1)ⓜ$%î⅋$%í?⍘.:⍘o)⨝ċɼ(`o⦃⍘.ĘМũ⁽îí-1)}o”,↪$ú⬮

Try it here (Firefox only).

Deve haver uma maneira de jogar isso ainda mais!

Explicação

Este é um algoritmo bifásico básico. Na verdade, é bastante simples.

Fase 1

⩥Мū⁽îí+1)ⓜ$%î⅋$%í?⍘.:⍘o)⨝

Primeiro, criamos um intervalo de 0 a LCM + 1. Em seguida, mapeamos sobre ele, verificando se uma das entradas é um fator do item atual no intervalo. Nesse caso, substituímos esse item por um o; caso contrário, substituí-lo por a .. A união nos dá uma série de O's e pontos que podemos passar para a fase dois.

Fase 2

ċɼ(`o⦃⍘.ĘМũ⁽îí-1)}o”,↪$ú⬮

Esta é apenas uma grande função de substituição. Um regex é criado como o[dots]o, onde a quantidade de pontos é determinada pelo GCD-1. Como esse regex não é global, ele corresponderá apenas à primeira ocorrência. Depois, a correspondência é substituída O[dots]Ousando uma função toUpperCase.

Mama Fun Roll
fonte
3

MATL , 72 bytes

Usa a versão 6.0.0 , que é anterior a esse desafio. O código é executado no Matlab e no Octave.

2$tZm1+:1-bbvtbw\A~otbZ}ZdXK1+ltb(3X53$X+1K2$lh*t2=f1)tK+hwg1+Ib('.oO'w)

Exemplo

>> matl
 > 2$tZm1+:1-bbvtbw\A~otbZ}ZdXK1+ltb(3X53$X+1K2$lh*t2=f1)tK+hwg1+Ib('.oO'w)
 > 
> 1
> 1
OO

>> matl
 > 2$tZm1+:1-bbvtbw\A~otbZ}ZdXK1+ltb(3X53$X+1K2$lh*t2=f1)tK+hwg1+Ib('.oO'w)
 > 
> 2
> 3
o.OOo.o

>> matl
 > 2$tZm1+:1-bbvtbw\A~otbZ}ZdXK1+ltb(3X53$X+1K2$lh*t2=f1)tK+hwg1+Ib('.oO'w)
 > 
> 12
> 15
o...........O..O........o.....o.....o........o..o...........o

Explicação

Não tenho ideia de como isso funciona. Eu apenas digitei caracteres aleatoriamente. Eu acho que há alguma convolução envolvida.

Edit: Experimente online! O código no link foi ligeiramente modificado para estar em conformidade com as alterações no idioma (em 2 de junho de 2016).

Luis Mendo
fonte
Você não pode digitar um programa de 72 bytes aleatoriamente. Irá calcular a probabilidade mais tarde (depois de dormir e agir por um tempo)
CalculatorFeline
2

Japonês , 83 bytes

'.pD=U*V/(C=(G=@Y?G$($YX%Y :X} $($UV)+1 £Y%U©Y%V?".:o"} $.replace($E=`o{'.pC-1}o`Eu

Ainda não totalmente jogado de golfe ... E não quer ser jogado de golfe: /

nicael
fonte
Você não pode usar rno lugar de $.replace($?
ETHproductions
@Eth Eu não descobri como substituir sem a bandeira g, então não, eu não posso.
Nicael
2

Javascript, 170 164 161 153 153 145 141 136 bytes

(a,b)=>[...Array(a*b/(c=(g=(a,b)=>b?g(b,a%b):a)(a,b))+1)].map((x,i)=>i%a&&i%b?'.':'o').join``.replace(`o${e='.'.repeat(c-1)}o`,`O${e}O`)

Isso é bastante lonnnggggg ....

Demonstração , variáveis ​​definidas explicitamente porque o intérprete usa o modo estrito.

nicael
fonte
Tente substituir i%a<1||i%b<1?'o':'.'pori%a&&i%b?'.':'o'
Mama Fun Roll
Ah, sim, acho que você pode se juntar.
Mama Fun Roll
Obrigado, também substituindo arrays por repetição simples.
Nicael
Ah, nesse caso, você provavelmente não deve associar um alias a menos que tenha 3 ocorrências.
Mama Fun Roll
[...Array((d=a*b/(c=(g=(a,b)=>b?g(b,a%b):a)(a,b)))+1).keys()].map(i=>i%a&&i%b?'.':'o')economiza dois bytes. (Eu também tentei indexação seqüência de uso para criar o e 'o', mas que na verdade custa dois bytes ''.)
Neil
1

Python 2, 217 200 191 bytes

Isso é um pouco franco, mas funciona. Todas as dicas de golfe são apreciados, especialmente se você sabe como corrigir isso s[i] = s[v] = "o"problema que encontramos, onde que iria substituir "O" s Got it!

g=lambda a,b:b and g(b,a%b)or a
def f(a,b):
 h=g(a,b);x=1+a*b/h;s=["."]*x;v=k=0
 for i in range(x):
    if(i%a)*(i%b)<1:
     if k:s[i]="o"
     else:k=i==h+v;s[i]=s[v]="oO"[k]
     v=i
 return''.join(s)

Ungolfed:

def gcd(a,b):                           # recursive gcd function
    if b:
        return g(b,a%b)
    else:
        return a
def f(a,b):
    h = gcd(a,b)
    x = 1 + a*b/h                       # 1 + lcm(a,b)
    s = ["."] * x
    v = 0
    k = 0
    for i in range(x):
        if i%a == 0 and i % b == 0:
            if k == 0:
                k = (i == h+v)          # correct distance apart?
                if k:                   # if "O" just found
                    s[i] = s[v] = "O"
                else:
                    s[i] = s[v] = "o"
            else:
                s[i] = "o"              # if "O" already found, always "o"
            v = i                       # If we found an "o" or an "O", i is the new v
    return ''.join(s)
Sherlock9
fonte