Conversão perfeita de quadrado para hexágono

23

Para muitos jogos disputados em uma grade, os hexágonos são a Claramente Superior Choice ™. Infelizmente, muitos sites de arte de jogos gratuitos possuem apenas conjuntos de blocos sem costura para mapas quadrados. Em um projeto passado, usei alguns deles e os converti manualmente em hexágonos.

No entanto , fiquei preguiçoso na velhice. Deve ser fácil automatizar o processo com um pequeno script.

No entanto , fiquei preguiçoso na velhice. Portanto, estou terceirizando para você e disfarçando-o como um desafio de código de golfe 1 .


Entrada

A entrada é uma imagem quadrada em qualquer formato de imagem comum capaz de cores RGB de 24 bits. Você também pode usar um nome de arquivo como entrada em vez dos próprios dados da imagem.

Você pode assumir que a imagem é quadrada e que o comprimento lateral é múltiplo de quatro.

Saída

A saída é o bloco de entrada, mas convertido em um hexágono (a própria imagem será quadrada, com áreas transparentes). Você pode salvá-lo em um arquivo ou exibir na tela.

Novamente, qualquer formato de imagem comum servirá. Se o formato que você estiver usando suportar transparência, as áreas de segundo plano deverão ser transparentes. Caso contrário, você pode usar a cor # FF00FF (aquela horrível cor de fúcsia) como substituta.

Método

Então, como fazemos isso? O método que eu uso 2 esmaga a imagem um pouco verticalmente, mas no geral parece muito bom para a maioria das coisas. Vamos fazer um exemplo com esta imagem de entrada:

entrada

  • Escala: Escale a imagem para uma proporção de 3: 2. Como nossas imagens serão quadrados, isso significa que você as dimensiona para 75% de largura e 50% de altura. Como nosso exemplo de entrada é 200x200, acabamos com esta imagem de 150x100:

esmagado

  • Lado a lado: Coloque cópias da imagem em escala em uma grade 2x2:

grade

  • Cortar: Pegue um hexágono de tamanho apropriado de qualquer lugar nesta grade 2x2. Agora, para facilitar a telha, esse hexágono não é exatamente regular. Depois de cortar um quadrado do tamanho original (aqui 200x200), você corta os cantos. As linhas de corte devem percorrer (aproximadamente) o centro de cada lado esquerdo / direito a um quarto da borda na parte superior / inferior:

hex

E essa é a sua saída!

Aqui está um exemplo de como pode parecer quando ladrilhado (ampliado aqui):

lado a lado

Este é o código golf, pelo que o código mais curto em bytes vence. Aplicam-se brechas padrão, etc. e assim por diante.


1 Sinta-se livre para acreditar nisso ou não.
2 Método um deste site útil.

Geobits
fonte
13
Esta pergunta está implorando por uma resposta Hexagony.
Sanchises
22
@sanchises Boa sorte.
Martin Ender
17
É aí que a segunda parte do Hex Agony se torna importante.
flawr
2
@ mbomb007 Provavelmente, embora o verde # 00FF00 que é usado às vezes não seja tão ruim assim. Ainda assim, sinto que eles usam fúcsia com mais frequência, porque ninguém em sã consciência desejaria a cor exata em seus sprites, por isso é bastante universal: P
Geobits
3
# 3 - eu espero neste pacientemente para ver os algoritmos fresco gerado ... então suavemente e com amor "borrow"-los para os meus usos ;-)
scunliffe

Respostas:

10

Matlab, 223 215 209 184 163 bytes

O redimensionamento é bastante direto. Para cortar os cantos, sobreponho um sistema de coordenadas sobre os pixels e faço uma máscara através de quatro desigualdades lineares, que determinam a área do hexágono.

​l=imread(input(''));
u=size(l,1);
L=imresize(l,u*[2 3]/4);
L=[L,L;L,L];L=L(1:u,1:u,:);
[x,y]=meshgrid(1:u);
r=u/2;x=x*2;
set(imshow(L),'Al',y<x+r&y+x>r&y+x<5*r&y>x-3*r)

insira a descrição da imagem aqui

PS: Isso se transformou em um jogo de codegolf nim com a participação de @ MartinBüttner: você alternativamente precisa tornar seu código mais curto (ao mesmo tempo em que fornece a mesma funcionalidade) - aquele que pode fazer o último 'encurtamento' vencer =)

flawr
fonte
Você pode salvar 5 bytes alterando o cálculo da escala de redimensionamento para [k.*[2 3]/4].
copo
4
As áreas de fundo não deveriam ser fúcsia, não pretas?
Blackhole
Graças @Blackhole para me deixar saber, eu fixa-lo agora, ainda salvou-me bastante um monte de bytes =)
flawr
12

Mathematica, 231 211 209 208 201 188 173 bytes

ImageCrop[ImageCollage@{#,#,#,#},e,Left]~SetAlphaChannel~ColorNegate@Graphics[RegularPolygon@6,ImageSize->1.05e,AspectRatio->1]&@ImageResize[#,{3,2}(e=ImageDimensions@#)/4]&

Esta é uma função sem nome que pega um objeto de imagem e retorna um objeto de imagem:

insira a descrição da imagem aqui

Acho que não há muito o que explicar aqui, mas alguns detalhes que são importantes:

  • Normalmente, para ladrilhar uma imagem 2x2, você usaria ImageAssemble[{{#,#},{#,#}}], ou seja, entregaria ImageAssembleuma matriz 2x2 com cópias da imagem. No entanto, existe ImageCollagealgum tipo de função mágica que tenta organizar um monte de fotos o mais "possível" (o que quer que isso signifique ... você pode até dar pesos e outras coisas às imagens individuais). De qualquer forma, você fornece quatro imagens de tamanho igual e com pesos iguais (ou nenhum), também as organizará em uma grade 2x2. Isso me permite salvar alguns bytes para o aninhamento da matriz, bem como o nome da função.
  • O hexágono é renderizado como um único polígono via Graphics. Estou usando o built-in RegularPolygon@6, mas imponha uma proporção 1para esticá-lo conforme necessário. Infelizmente, Graphicsprecisa de algumas opções caras para evitar o preenchimento e tal, e também torna preto no branco em vez do oposto. O resultado é fixado ColorNegatee anexado aos canais originais da imagem com SetAlphaChannel.
  • Graphicscoloca uma pequena quantidade de preenchimento ao redor do hexágono, mas queremos que o hexágono alfa cubra todo o tamanho do recorte. No entanto, SetAlphaChannelpode combinar imagens de tamanhos diferentes, centralizando-as umas sobre as outras e cortando-as no menor tamanho. Isso significa que, em vez de configurar manualmente PlotRangePadding->0, podemos simplesmente ampliar um pouco a imagem do hexágono ImageSize->1.05e(e precisamos da opção `ImageSize de qualquer maneira).
Martin Ender
fonte
5

HTML5 + Javascript, 562 bytes

<html><form><input type=text></form><canvas><script>l=document.body.children;l[0].addEventListener("submit",e=>{e.preventDefault();c=l[1].getContext("2d");i=new Image();i.onload=q=>{l[1].width=l[1].height=d=i.width;c.scale(0.75,0.5);c.drawImage(i,0,0);c.drawImage(i,d,0);c.drawImage(i,0,d);c.drawImage(i,d,d);c.globalCompositeOperation="destination-in";c.scale(1/0.75,2);c.beginPath();c.moveTo(d/4,0);c.lineTo(d/4+d/2,0);c.lineTo(d, d/2);c.lineTo(d/4+d/2, d);c.lineTo(d/4, d);c.lineTo(0, d/2);c.closePath();c.fill();};i.src=e.target.children[0].value;})</script>

Recebe a entrada como um URL da imagem via caixa de texto (esperamos que o URL conte como nome de arquivo). Envia os dados para a tela.

Versão que funciona em todos os navegadores (580 bytes):

<html><form><input type=text></form><canvas><script>l=document.body.children;l[0].addEventListener("submit",function(e){e.preventDefault();c=l[1].getContext("2d");i=new Image();i.onload=function(){l[1].width=l[1].height=d=i.width;c.scale(0.75,0.5);c.drawImage(i,0,0);c.drawImage(i,d,0);c.drawImage(i,0,d);c.drawImage(i,d,d);c.globalCompositeOperation = "destination-in";c.scale(1/0.75,2);c.beginPath();c.moveTo(d/4, 0);c.lineTo(d/4+d/2,0);c.lineTo(d, d/2);c.lineTo(d/4+d/2, d);c.lineTo(d/4, d);c.lineTo(0, d/2);c.closePath();c.fill();};i.src=e.target.children[0].value;})</script>

Teste-o com a imagem "bloqueia" anteriormente através deste URL: http://i.stack.imgur.com/gQAZh.png

adroitwhiz
fonte
Bom trabalho! Você pode salvar alguns bytes adicionando id=Aao <form>e id=Bao <canvas>, substituindo l[0]por Ae l[1]com Be removendo l=document.body.children;. (Funciona no Firefox 41; não tenho certeza de quais outros navegadores suportam isso.) Além disso, acredito que há alguns pontos e vírgulas desnecessários ao lado dos colchetes direitos e alguns espaços extras.
ETHproductions
Mais dicas: acredito que você pode adicionar id=Cao <input>e substituir e.target.children[0]por C. 0.75é igual a 3/4, 1/0.75é igual a 4/3, d/4+d/2é igual a d*3/4, e os zeros à esquerda nos outros decimais não são necessários. Eu também acredito que você poderia substituir o primeiro c.drawImagepor c[p="drawImage"], e depois cada um por c[p]; você poderia fazer o mesmo com c.lineTo.
ETHproductions
4

Python 2 + PIL, 320

Lê o nome do arquivo de imagem de stdin.

from PIL import ImageDraw as D,Image as I
i=I.open(raw_input())
C=A,B=i.size
i,j=i.resize((int(.75*A),B/2)),I.new('RGBA',C)
W,H=i.size
for a,b in[(0,0),(0,H),(W,0),(W,H)]:j.paste(i,(a,b,a+W,b+H))
p,d=[(0,0),(A/4,0),(0,B/2),(A/4,B),(0,B)],lambda p:D.Draw(j).polygon(p,fill=(0,)*4)
d(p)
d([(A-x,B-y)for x,y in p])
j.show()
dieter
fonte
É verdade, desculpe-me por isso, não foi PILútil para tentar e não pensei o suficiente. Ainda
mantenho
2

PHP, 293 bytes

Adicionei algumas novas linhas para facilitar a leitura:

function($t){$s=imagesx($t);imagesettile($i=imagecreatetruecolor($s,$s),$t=imagescale
($t,$a=$s*3/4,$b=$s/2));imagefill($i,0,0,IMG_COLOR_TILED);$z=imagefilledpolygon;$z($i,
[0,0,$s/4,0,0,$b,$s/4,$s,0,$s],5,$f=imagecolorallocate($i,255,0,255));$z($i,[$s,0,$a,
0,$s,$b,$a,$s,$s,$s],5,$f);return$i;}

Aqui está a versão não destruída:

function squareToHexagon($squareImage)
{
    $size = imagesx($squareImage);
    $tileImage = imagescale($squareImage, $size * 3/4, $size/2);

    $hexagonImage = imagecreatetruecolor($size, $size);
    imagesettile($hexagonImage, $tileImage);
    imagefill($hexagonImage, 0, 0, IMG_COLOR_TILED);

    $fuchsia = imagecolorallocate($hexagonImage, 255, 0, 255);
    imagefilledpolygon(
        $hexagonImage,
        [
            0,       0,
            $size/4, 0,
            0,       $size/2,
            $size/4, $size,
            0,       $size,
        ],
        5,
        $fuchsia
    );
    imagefilledpolygon(
        $hexagonImage,
        [
            $size,       0,
            $size * 3/4, 0,
            $size,       $size/2,
            $size * 3/4, $size,
            $size,       $size,
        ],
        5,
        $fuchsia
    );

    return $hexagonImage;
}

header('Content-type: image/gif');
$squareImage = imagecreatefrompng('squareImage.png');
$hexagonImage = squareToHexagon($squareImage);
imagegif($hexagonImage);
Blackhole
fonte