Saída de uma face em um cubo numerado
Atribua os números de 0 a 7 aos 8 vértices de um cubo da maneira que desejar. Exatamente um número deve ser atribuído a cada vértice.
Por exemplo, seus vértices podem ser atribuídos assim:
Escreva um programa que inclua um número inteiro de 0 a 5. Cada um desses 6 números está associado a exatamente uma face do seu cubo da maneira que desejar. Quando um desses números é inserido, os 4 números de vértices da face associada devem ser impressos em stdout em um quadrado de 2 × 2 dígitos. O rosto deve ser visto diretamente de fora do cubo. Todas as 4 rotações da face são válidas.
Por exemplo, se 0 estiver associado à face frontal do cubo de exemplo acima, isso seria uma saída válida para entrada 0:
A face pode ser vista a qualquer rotação de 90 °, portanto, estas também são válidas:
Esta saída (e suas rotações) não são válidas , pois são visualizadas do lado errado da face:
A mesma idéia se aplica a todas as outras faces. por exemplo, se 1 estiver associado à face traseira, a entrada 1poderá produzir saída 13[newline]05(e 31[newline]50seria inválida).
Portanto, o verdadeiro desafio é escolher seus números e rotações de vértices, de modo que a conversão da entrada em seus quatro números seja fácil e curta.
O código mais curto em bytes vence. O desempatador é um post anterior. ( Contador de bytes acessíveis ) .
Você pode escrever uma função em vez de um programa. Ele deve levar um número inteiro de 0 a 5 e imprimir ou retornar a cadeia de grade de 2 × 2 dígitos.
Obtenha entrada de stdin, linha de comando ou função arg. Você pode assumir que a entrada é válida.
Não deixe de nos dizer o número do vértice e do rosto que você escolheu.
Provavelmente existe uma solução matemática elegante para esse problema. Mas eu não tenho idéia de como encontrar um, então é um código super compactado!
Eu encontrei um! Bem, não é uma solução matemática classicamente elegante, pois usa operações bit a bit, mas é totalmente fórmula.
Layout do cubo
Minha resposta antiga já expôs o cubo de forma que cada face possa ser descrita com seu primeiro número de vértice (canto superior esquerdo) igual ao número da face. Mas eu queria poder calcular mais números de vértices usando o número da face. Em algum momento, tive a idéia de colocar meu pé na porta, para calcular o segundo número de vértice (canto superior esquerdo) como o número de face XOR 1. E depois de um tempo de tentativa e erro, consegui surgir com o layout mostrado acima e as fórmulas abaixo que permitem calcular de forma sucinta todos os números de vértices de um rosto n:
Superior esquerdo: n
Canto superior direito: n^1
Inferior esquerdo: (n^1)|6
Canto inferior direito: ((n^1)+3)%6
Para referência, reproduzirei a saída de cada face no layout desejado aqui:
Portanto, todo o programa se resume a ler o número da face de entrada e produzir esses valores em ordem, embora com uma lógica de impressão ligeiramente diferente para vértices diferentes. Observe que, como todo vértice após o primeiro começa com uma base de n^1, eu só preciso calcular isso uma vez, o que compacta a lógica ainda mais.
Pelo bem da posteridade, e porque acho que ainda era uma abordagem muito boa, aqui está minha antiga resposta.
A abordagem básica empregada é codificar os vértices para cada face no menor espaço possível. De maneira semelhante à solução de conversão básica do Optimizer, isso trata a lista de vértices como um número octal compactado como dados de caracteres ASCII. Mas é aí que as semelhanças terminam para abrir caminho para novas otimizações!
Aqui estão as três principais otimizações que fiz para a solução "ingênua":
Disponha o cubo de forma que cada face possa ser descrita com seu número de face como o primeiro número de vértice. Observando meu layout de cubo, como apresentado acima, é possível ver que o número do vértice no canto superior esquerdo de cada face é igual ao número da face. Isso me permite codificar seis menos vértices ao custo de imprimir a entrada novamente, o que acaba salvando um byte.
Empacote os dados do vértice em uma cadeia de caracteres para a qual cada "caractere" tenha um máximo maior que 256. Como esse máximo aumenta além de 256, o comprimento da cadeia diminui lentamente, mas torna-se cada vez mais provável que qualquer "caractere" exceda 256 e é portanto, não faz mais parte do conjunto de caracteres ASCII de 1 byte. Então, escrevi um programa que tenta codificar os dados de vértices em todas as bases, de 256 a 1000, com os quais encontrei cerca de 10 bases que salvam um byte de dados de caracteres em comparação com a base 256. Escolhi 487, pois também possui a propriedade nice a sequência resultante consiste inteiramente em ASCII imprimível.
Misturado com a primeira otimização, produza a saída assimetricamente. A abordagem usual no CJam seria formatar os dados do vértice como uma lista de 2 elementos, inserir uma nova linha no meio e deixar a saída ser impressa implicitamente. Mas, em vez disso, imprimo o primeiro vértice (igual ao número da face de entrada) com um operador que não adiciona uma nova linha, recupero a lista de 3 elementos dos outros vértices, agarro o próximo vértice e imprimo-o com um operador que adiciona uma nova linha e deixe que os outros dois vértices sejam impressos implicitamente. Isso economiza um byte.
Tentei permutações como uma abordagem matemática elegante e é mais detalhada do que a codificação sem suas otimizações.
Sua resposta mais recente é brilhante. Eu acho que você deveria ter postado isso como uma resposta separada, pois é uma abordagem completamente diferente e digna de outro voto positivo. Basicamente, você tem o mesmo cubo da minha resposta C, mas com os três primeiros cantos pares mudou um lugar. Não acredito que errei 6+n%2 --> 6|n(já incorporei isso na minha resposta Ruby.) Observe que, ao realizar a transformação n --> n^1nas faces, você pode simplificar suas fórmulas, embora eu esteja supondo que, ao descartar ne continuar, n^1ela ganhou ajude sua pontuação.
@steveverrill Obrigado pelo elogio! Perguntei no chat se eu deveria postar isso como uma resposta totalmente nova, mas não havia um consenso, então não o fiz. Definitivamente, fiquei satisfeito comigo mesmo quando percebi que ordenar cuidadosamente os pares ne n^1ao redor do cubo me permitiria calcular outro vértice com apenas |6. E não vi essa n --> n^1transformação, o que definitivamente faz sentido. Mas você corretamente supôs que isso não afetaria minha pontuação, então provavelmente vou deixar como está.
Fui em frente e incorporei sua ideia XOR na minha resposta Ruby. Dá uma economia de 10 (além dos 2 para 6+n%2 --> 6|n) Espero que você não se importe. Eu usei a n --> n^1transformação nas faces, portanto, minha revisão mais recente fornece as mesmas saídas que a sua, mas com entradas diferentes. BTW, eu não acho que operações de bits são deselegantes, tudo depende de como você as usa!
1 caractere mais curto no GolfScript:~.1^..n@6|@3+6%
Minha numeração de cubo, quando desdobrada, fica assim:
O canto superior esquerdo tem o mesmo número que o rosto.
O canto inferior direito tem o número (n+2)%6
Para ímpar, no canto superior direito é (n+1)%6e o canto inferior esquerdo é6
Até mesmo no canto superior direito é 7e o canto inferior esquerdo é(n+1)%6
O programa exibe os números ímpares, como mostrado, e os números pares, girados 180 graus. Isso significa que o canto superior direito é sempre (n+1)%6e o canto inferior esquerdo é sempre (n+1)%2+6. Inverter ne n+2é mais fácil (isso é feito configurando c=n+1e usando dpara adicionar ou subtrair 1ou -1conforme necessário.)
+1 Este é o tipo de solução matemática elegante que eu estava imaginando. Infelizmente, ele é implementado em C ...
@ Runer112 Obrigado. Infelizmente, C é o idioma que eu conheço melhor. Estou aprendendo Ruby, mas ainda sou iniciante. Ruby deve ser capaz de esmagar essa pontuação, mas provavelmente não competirá com Cjam. Talvez eu vou postar em Ruby mais tarde, ou apenas encontrar algumas pequenas melhorias para a minha resposta C (por exemplo, alterando c%6a c%=6e girando o rosto para que ele vem em primeiro lugar, deve ser possível eliminar alguns cálculos módulo.) Outra coisa a experimentar é mudando a rotulagem do rosto por um lugar, então eu fico em n-1,n,n+1vez de n,n+1,n+2.
@steveverrill você já está declarando nglobal, para poder salvar alguns bytes declarando-o mais alto, altere a assinatura para f()? Ou estamos apenas olhando para a ffunção aqui?
@dwcanillas "You may write a function instead of a program"então estou contando apenas a função. De qualquer forma, essa foi apenas uma prova de conceito na linguagem com a qual estou mais familiarizado. Estou mais interessado em encurtar minha resposta Ruby, que desde o início já era muito mais curta que isso.
Diferentemente de muitas linguagens de golfe mais avançadas, a Element não possui um operador de compactação, portanto a brevidade da solução está intimamente ligada ao esquema de numeração exato usado. Após algumas experiências, criei um novo esquema de numeração que permite que os vértices sejam computados usando apenas operações aritméticas simples.
O canto superior esquerdo é 6 se for par e 7 se for ímpar. O canto superior direito é o próprio número da face. O canto inferior esquerdo é o número da face, mais 2, mod 6. O canto inferior direito é 5 menos o número da face.
Aqui está uma explicação do código.
Aqui estão as saídas para cada uma das faces:
+1: embora eu ache seu código indecifrável, é bom ver como isso ocorre em um idioma de golfe. Parece que você está atualmente no 3º lugar conjunto, atrás de 2 respostas do CJam: Peter Taylor e Runer 112.
Agora está em um sólido segundo lugar, mas não prevejo que ele derrote CJam.
Oitava, 108 100 68 50 bytes
É claro que existe uma maneira de fazê-lo de maneira muito mais elegante do que minhas abordagens anteriores, simples codificação. Estou surpreso como o Octave é muito mais adequado para codegolf do que o Matlab =)
(Desculpe, esqueci de adicionar isso.)
Versões ainda mais antigas:
Isso realmente criará uma matriz 2x2x2 e depois escolherá uma 'fatia'. Fazemos uma permutação de matriz 3d e sempre escolhemos a fatia superior ou inferior. (Este não funciona no matlab por causa da indexação de uma expressão, e não de uma matriz). Tenho certeza de que haveria maneiras mais diretas de fazê-lo, que seriam mais curtas.
CJam, 31 28 (ou 26) bytes
que também pode ser compactado usando a conversão base em uma versão de 26 bytes .
Assume que o cubo seja como:
com rostos como
Ele contém um caractere não imprimível e uma guia (que será confinada pelo software StackExchange), portanto no formato xxd:
É pura codificação, com os vértices do cubo selecionados para maximizar a compressibilidade da base. Decodifico para números de 2 dígitos, para que nenhum deles comece com 0. Também não quero que comece com 7, pois isso eleva a segunda base muito alto. Portanto, 0 e 7 devem estar em uma diagonal longa. Quero que uma borda 10 seja a primeira a reduzir o valor que estou codificando. Fora isso, há uma boa quantidade de flexibilidade sem alterar a contagem de bytes.
Estou um pouco decepcionado por ter retirado o primeiro caractere da sequência mágica, é necessário convertê-lo em um int antes de usá-lo como base para a conversão de base. Esperamos que versões futuras do CJam salvem esse byte, embora seja tarde demais para explorá-lo aqui.
Editar Salve 8 bytes usando seqüências de caracteres de modelo, thx @NinjaBearMonkey. Cuidado, as novas linhas entre aspas são significativas e não podem ser recolhidas.
Não pode ser inteligente em Javascript, é muito detalhado.
Resultado for(i=0;i<6;i++)console.log(f(i),i)
Veja o snippet para veicular as associações numéricas ( isso foi divertido)
Se você usar cadeias de modelo do ES6 , poderá usar caracteres de nova linha acionais em vez de \n, o que deve salvar 8 bytes.
Você deve usar marcas de escala `em vez de aspas para as seqüências de caracteres do modelo.
Certo, foi assim que testei de fato.
Rubi Rev 1, 40 36
Obrigado a @rcrmn por sugerir o uso de um lambda para economizar 4 bytes. Eu não tinha certeza de deixá-lo anônimo, mas parece ter sido discutido na meta aqui e decidido que isso estava OK.
Aqui está como uma função de 40 bytes, para comparação com a minha resposta Rev 0 Ruby, também abaixo (a resposta C original está em um post separado.)
Mais inspiração do Runer112: Isso depende de uma modificação do esquema de numeração usado em sua resposta mais recente (16 bytes!). Uma porta direta do esquema do PhiNotPi daria a mesma pontuação.
Alterando a numeração do Rev 0 em uma etapa e executando tudo o XOR 1, obtemos o seguinte cubo:
Salvo 4 bytes por remoção unnecesary ()%6do c-de outro 2 (inspirado runer112) por 6+c%2 --> 6|c.
A pontuação é para a função, que é apenas a primeira linha. Sou novo em Ruby e estou surpreso por não encontrar uma maneira menor que 12 caracteres (11 mais nova linha) para inserir um número de entrada do usuário em n. Como resultado, executar uma função em vez de um programa economiza 1 byte.
Esta é uma porta da minha resposta C. Em C, o %operador retorna um valor negativo com um número negativo. No Ruby, ele sempre retorna um valor positivo; portanto, não há necessidade de adicionar 1 a c. Como resultado, é vantajoso alterar a numeração das faces por 1, conforme abaixo:
Com a nova numeração de faces, o programa imprime os pares, como mostrado acima, e as chances rodam 180 graus:
Eu acredito que você pode encurtar a função usando lambdas: o ->(x){...code...}que deixa sua definição de função 4 caracteres mais curta. Você então tem que atribuí-la a uma variável para usá-lo e chamá-lo com #CALL
@ rcrmn obrigado, você está certo, f=->(c){print(c^1,c,"\n",6|c,(c+3)%6)}é executado e tem 2 caracteres a menos (4 caracteres a menos se eu omitir o f=). Não tenho certeza se é justo omitir, f=mas a pergunta não diz que a função não pode ser anônima. O que eu acho estranho é que essa sintaxe é totalmente diferente da sintaxe mostrada para iniciantes, que possui o parâmetro passado dentro do aparelho:f=lambda{|c|print(c^1,c,"\n",6|c,(c+3)%6)}
Isso é chamado de literal lambda. E, na verdade eu sempre acham difícil encontrar uma referência quando eu preciso lembrar a sintaxe ...
Obrigado @Jakube por 2 bytes.
Os conselhos de especialistas em golfe serão gentilmente aceitos. Em particular, acho que a seção de saída pode ter algumas melhorias.
Porta do seguinte python: ...
... que é um porto de
Para fins de explicação:
Os vértices do cubo são numerados assim:
E os rostos são numerados assim:
A Swapcoluna indica que a ordem dos vértices deve ser alternada na saída.
O algoritmo começa com todos os vértices {0..7}. Os vértices são eliminados de acordo com os bits definidos nos números dos vértices:
Para as faces 0,1 e 2, os vértices com os bits 1,2 ou 3 limpos respectivamente são mantidos
Para as faces 3,4 e 5, os vértices com os bits 1,2 ou 3 definidos respectivamente são mantidos
Os vértices "mantidos" são anexados a uma sequência. A string é caracteres de saída 0,1 e 2,3 ou vice-versa, dependendo se o sinalizador de troca (número da face mod 2) está definido.
Função tomando o número da face como argumento e retornando a grade de dígitos.
Estamos usando o seguinte cubo:
Exemplo (tente você mesmo em tryj.tk ):
O pão com manteiga é 0&(|:|.). Este é um verbo que inverte e gira o cubo de forma a visitar todas as faces quando aplicadas iterativamente, que é o que fazemos usando o argumento de entrada. Os vértices do cubo são gerados por i.3#2, portanto, usamos isso como ponto de partida e assumimos a face frontal 0...{quando terminamos.
Imprimir os dígitos como uma string custa 8 caracteres: {.@":"0@se pudéssemos simplesmente devolver uma matriz, isso economizaria 8 caracteres inteiros. [começa a tremer os punhos e o aperto indiscernível]
Os resultados de 1, 4 e 5 parecem ter sido revertidos
> <> (Peixe) , 38 bytes
Cada saída é armazenada como duas linhas de 2 dígitos. As linhas são armazenadas como códigos na string '/ =/2= 28"H'(exceto a linha 10que é anexada após a string comoa ). O primeiro caractere ( / = 47) é usado para redirecionar o fluxo do programa na segunda interação.
O topo 2*(53-n) elementos são descartados (onde n é o código do número de entrada) e os próximos dois códigos são impressos com uma nova linha no meio.