Arte ASCII anti-aliasing


33

fundo

A arte ASCII é a prática de criar imagens usando texto ASCII para formar formas.

Alias ​​é o efeito criado pelos grandes "pixels" da arte ASCII, que são do tamanho de caracteres. A imagem fica com blocos e difícil de ver. A suavização de serrilhado remove esse efeito criando um gradiente e suavizando as arestas rígidas da arte ASCII.

O desafio

Seu desafio é escrever o programa mais curto possível, que terá uma obra de arte ASCII e produzirá uma versão com anti-alias.

Que tipo de anti-aliasing?

Toda a arte ASCII consistirá em dois tipos de símbolos: Espaços e espaços não em branco. Para cada caractere que não seja um espaço em branco, seu programa deve determinar se está em uma posição em que precisa ser suavizado. Se for, é necessário substituí-lo pelo caractere correto. Se não for, o personagem permanece o mesmo.

Como você sabe se um personagem precisa ser anti-alias? A resposta depende dos caracteres imediatamente acima, abaixo, esquerda e direita do caractere ( não nas diagonais ). Aqui está um gráfico de quando o anti-aliasing é necessário, onde ?e xpode representar qualquer caractere que não seja um espaço em branco.

 x? ->  d?
 ?      ? 


?x  -> ?b 
 ?      ? 

 ?      ? 
?x  -> ?F 


 ?      ? 
 x? ->  Y?



 x  ->  ;   Note: This character has been changed from _ to ;
 ?      ? 

 ?      ? 
 x  ->  V 



?x  -> ?> 



 x? ->  <?



 x  ->  @ 

Entrada (e exemplo de arte ASCII pré-anti-aliasing)

Primeiro, haverá duas linhas de entrada (para STDIN), um número H seguido de um número W. Haverá, então, linhas H com exatamente W caracteres cada (excluindo a nova linha). Estas linhas a seguir serão a arte ASCII que precisa ser anti-alias. Aqui está um exemplo de entrada (não bonito, mas um teste):

7
9
  888888 
 888888  
999 98  7
 666666  
  666666 
   6666  
    6    

Saída (e exemplo arte anti-alias)

Seu programa deve gerar para STDOUT a arte ASCII (das mesmas dimensões), que foi anti-alias. Aqui está a saída para a entrada acima. Observe como os caracteres de borda são tratados como espaços em branco.

  d8888> 
 d8888F  
<99 98  @
 Y6666b  
  Y6666> 
   Y66F  
    V    

Isso pode não parecer tão bom (devido ao espaço entre as linhas no bloco de código), fica melhor com arte ASCII maior e a qualidade depende da fonte exata usada.

Outro exemplo

Entrada

12
18
   xx  xxx  xxx   
  xxxx  xxx  xxx  
 xxxxxx  xxx  xxx 
xxx  xxx  xxx  xxx
xxxx xxx  xxx  xxx
 xxxxxx  xxx  xxx 
  xxxx  xxx  xxx  
x  xx  xxx  xxx  x
xx    xxx  xxx  xx
xxx  xxx  xxx  xxx
xxxx  xxx  xxx  xx
xxxxx  xxx  xxx  x

Saída

   db  <xb  <xb   
  dxxb  Yxb  Yxb  
 dxxxxb  Yxb  Yxb 
dxx  xxb  xxb  xxb
Yxxb xxF  xxF  xxF
 YxxxxF  dxF  dxF 
  YxxF  dxF  dxF  
;  YF  dxF  dxF  ;
xb    dxF  dxF  dx
xxb  <xF  <xF  <xx
xxxb  Yxb  Yxb  Yx
Yxxx>  Yx>  Yx>  V

Regras, restrições e notas

Seu programa deve ser escrito apenas em caracteres ASCII imprimíveis, para que possamos criar arte com os programas. Fora isso, as regras padrão de código de golfe se aplicam.


Como ainda não há respostas, alterei um caractere no gráfico de suavização de serrilhado. _tornou-se ;porque funciona melhor.
PhiNotPi

Esta pode ser a minha pergunta favorita sobre golfe de código de todos os tempos. Trabalhando em 4 soluções impressionantes diferentes.
Captncraig 12/04/12

Embora eu esteja confuso. Você diz que as diagonais não contam, mas todos os seus diagramas mostram pontos de interrogação preenchendo as diagonais. Pelo que vejo nos exemplos, pode ser seguro olhar apenas para os lados, mas fico confuso? As diagonais são importantes?
precisa saber é o seguinte

Não, as diagonais nunca importam. Provavelmente ficará mais claro se eu removi as diagonais do gráfico.
PhiNotPi 12/04

Eu acho que pode haver um erro de digitação no seu exemplo; Eu acredito que a coluna da direita deve ter Ys na borda interna. Gostei de chegar com a resposta para esta pergunta, porém: boa pergunta: D
Ed James

Respostas:


8

Ruby, 180 168 caracteres

gets
w=1+gets.to_i
f=*(readlines*"").chars
f.zip(f[1..-1]+s=[" "],s+f,s*w+f,f[w..-1]+s*w){|a,*b|$><<"@;V#{a}>bF#{a}<dY#{a*5}"[a>" "?(b.map{|y|y>" "?1:0}*"").to_i(2):3]}

Outra implementação Ruby que adota uma abordagem zip. Você pode ver o segundo exemplo em execução online .

Editar: o uso readlinessalva 12 caracteres.


6

Rubi 275 265 263 261 258 254 244 243 214 212 207

H=0...gets.to_i
W=0...gets.to_i
G=readlines
z=->x,y{(H===y&&W===x&&' '!=G[y][x])?1:0}
H.map{|j|W.map{|i|l=G[j][i]
G[j][i]="@V;#{l}>Fb#{l}<Yd#{l*5}"[z[i+1,j]*8+z[i-1,j]*4+z[i,j+1]*2+z[i,j-1]]if' '!=l}}
puts G

Amostra 1: http://ideone.com/PfNMA

Amostra 2: http://ideone.com/sWijD


1) Parênteses em torno da definição do intervalo não são necessários. 2) 0..h-1pode ser escrito como 0...h. 3) G=[];h.times{G<<gets}pode ser escrito como G=readlines, da mesma forma que no seu código C #. 4) Após o passo 3. a variável h se torna inútil, os valores de hew são usados ​​apenas uma vez, portanto h=gets.to_i;w=gets.to_i;H=(0..h-1);W=(0..w-1)podem ser escritos como H=0...gets.to_i;W=0...gets.to_i. 5) No presente caso andpode ser escrito como &&, que não precisa os espaços ao redor. 6) Você tem um extra; e você contou a nova linha no final do arquivo, que não é necessária. Isso significa 214 caracteres: ideone.com/CiW0l
manatwork

Uau, obrigada! Eu sabia que havia melhorias a serem feitas, mas nunca pensei que havia que muitos. Eu tentei H=0..gets.to_iquando escrevi o código, mas ele não parecia funcionar (obviamente, deve ter sido por outros motivos).
Cristian Lupascu

1
Ainda existem dois pontos em que você pode reduzir em pelo menos 7 caracteres: 1) Você pode usar em mapvez de each2) em z=->...vez de def z...end.
Howard

@ Howard Obrigado, eu apliquei o em mapvez de eachmudar. Para a sintaxe lambda, no entanto, acho que exigiria que o uso zfosse da forma em z.call(args)vez de z(args), adicionando um pouco à contagem de caracteres. Por favor, deixe-me saber se estou faltando alguma coisa.
Cristian Lupascu

@ Howard Nevermind, acabei de descobrir o que estava perdendo. Vou atualizar para usar o []uso lambda .
Cristian Lupascu

4

Javascript, 410 caracteres:

function(t){m={"10110":"b","11100":"d","01101":"Y","00111":"F","10100":";","00101":"V","00110":">","01100":"<","00100":"@"},d="join",l="length",t=t.split('\n').splice(2),t=t.map(function(x)x.split('')),f=function(i,j)t[i]?(t[i][j]||' ')==' '?0:1:0;for(o=t[l];o--;){for(p=t[o][l];p--;){y=[f(o+1,p),f(o,p+1),f(o,p),f(o,p-1),f(o-1,p)],t[o][p]=m[y[d]('')]||t[o][p]}}t=t.map(function(x)x[d](''))[d]('\n');return t;}

ungolfed:

function(t){
    m={
        "10110":"b",
        "11100":"d",
        "01101":"Y",
        "00111":"F",
        "10100":";",
        "00101":"V",
        "00110":">",
        "01100":"<",
        "00100":"@"
    },
    d="join",
    l="length",
    t=t.split('\n').splice(2),
    t=t.map(function(x) x.split('')),
    f=function(i,j) t[i]?(t[i][j]||' ')==' '?0:1:0;

    for(o=t[l];o--;){
        for(p=t[o][l];p--;){
            y=[f(o+1,p),f(o,p+1),f(o,p),f(o,p-1),f(o-1,p)],

            t[o][p]=m[y[d]('')]||t[o][p]
        }
    }
    t=t.map(function(x)x[d](''))[d]('\n');
    return t;
}

Original, 440 caracteres:

function (t){m={"10110":"b","11100":"d","01101":"Y","00111":"F","10100":";","00101":"V","00110":">","01100":"<","00100":"@"},s="split",d="join",l="length",t=t[s]('\n').splice(2),t=t.map(function(x) x[s]('')),f=function(i,j)i<0||i>=t[l]?0:(j<0||j>=t[i][l]?0:t[i][j]==' '?0:1);for(o=t[l];o--;){for(p=t[o][l];p--;){y=[f(o+1,p),f(o,p+1),f(o,p),f(o,p-1),f(o-1,p)],h=m[y[d]('')];if(h){t[o][p]=h}}}t=t.map(function(x) x[d](''))[d]('\n');return t;}

NB: Eu assumi que as duas primeiras linhas de entrada são realmente irrelevantes e o tamanho das seguintes linhas está correto. Também acho que talvez consiga cortar mais alguns caracteres quando tiver uma chance!


1
Substitua a declaração de m para m={22:"b",28:"d",13:"Y",7:"F",20:";",5:"V",6:">",12:"<",4:"@"}subscrito, em seguida, convertido de m com parseInt(): m[parseInt(y[d](''),2)]. Isso reduz o tamanho para 373 caracteres.
manatwork

3

Python, 259 caracteres

H=input()
W=input()+1
I=' '.join(raw_input()for i in' '*H)
for i in range(H):print''.join(map(lambda(s,a,b,c,d):(s*5+'dY<'+s+'bF>'+s+';V@'+' '*16)[16*(s==' ')+8*(a==' ')+4*(b==' ')+2*(c==' ')+(d==' ')],zip(I,I[1:]+' ',' '+I,I[W:]+' '*W,' '*W+I))[i*W:i*W+W-1])

O programa lê a entrada em uma única sequência de caracteres I(com espaços separando as linhas), fecha uma lista de cinco tuplas contendo o caractere e seus quatro caracteres adjacentes e, em seguida, pesquisa o caractere resultante usando a indexação de seqüências.


3

PHP - 359 330 282 268 257 caracteres

<?php
$i=fgets(STDIN)+0;$w=fgets(STDIN)+1;$s='';$m='@<;d>0b0VY00F000';
for(;$i--;)$s.=fgets(STDIN);
for(;++$i<strlen($s);){
$b=trim($s[$i])?0:15;
foreach(array($i+1,$i+$w,$i-1,$i-$w)as$k=>$x)
$b|=pow(2,$k)*(isset($s[$x])&&trim($s[$x]));
echo $m[$b]?$m[$b]:$s[$i];}

@PhiNotPi Não estava funcionando porque meus arquivos de teste salvos localmente tinham EOL no estilo do Windows \r\n. Atualizei meu código para trabalhar com EOL estilo unix \n.
Rusty Fausak

Ok, parece estar funcionando agora.
PhiNotPi 12/04/12

2

Pitão, 246 241

H=input();W=1+input()
S=' '
o=W*S
F=o+'\n'.join((raw_input()+o)[:W-1]for k in range(H))+o
print ''.join((16*x+'@;<d>b'+2*x+'V'+x+'Y'+x+'F'+3*x)[
16*(x>S)|8*(a>S)|4*(l>S)|2*(r>S)|(b>S)]for
x,a,l,r,b in zip(F[W:-W],F,F[W-1:],F[W+1:],F[2*W:]))

O WC e o teste na amostra 2 diferiram com a saída da solução Ruby na parte superior:

t:~$ wc trans.py && python trans.py < lala2 > o && diff -q o ruby_out2_sample
  2 11 241 trans.py
t:~$

1

C # 591 563

string A(string t){var s=new StringReader(t);var h=int.Parse(s.ReadLine());var w=int.Parse(s.ReadLine());var lines=s.ReadToEnd().Split(new[]{"\r\n"},StringSplitOptions.None).Select(x=>x.ToCharArray()).ToArray();for(var i=0;i<h;i++)for(var j=0;j<w;j++){var c=lines[i][j];if(c==' ')continue;var n=(i>0?(lines[i-1][j]!=' '?1:0):0)+(i<h-1?(lines[i+1][j]!=' '?2:0):0)+(j>0?(lines[i][j-1]!=' '?4:0):0)+(j<w-1?(lines[i][j+1]!=' '?8:0):0);lines[i][j]=new[]{'@','V',';',c,'>','F','b',c,'<','Y','d',c,c,c,c,c}[n];}return string.Join("\r\n",lines.Select(l=>new string(l)));}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.