ASCII antialiasing art


33

sfondo

L'arte ASCII è la pratica di creare immagini usando il testo ASCII per formare forme.

L'aliasing è l'effetto creato dai grandi "pixel" dell'arte ASCII, che sono le dimensioni dei caratteri. L'immagine diventa bloccata e difficile da vedere. L'antialiasing rimuove questo effetto creando un gradiente e ammorbidendo i bordi duri dell'arte ASCII.

La sfida

La tua sfida è quella di scrivere il programma più breve possibile che prenderà un pezzo di arte ASCII e produrrà una versione che è stata anti-alias.

Che tipo di anti-aliasing?

Tutta l'arte ASCII sarà composta da due tipi di simboli: spazi e non spazi bianchi. Per ogni personaggio non bianco, il tuo programma deve determinare se si trova in una posizione in cui deve essere anti-alias. In tal caso, è necessario sostituirlo con il carattere corretto. In caso contrario, il personaggio rimane lo stesso.

Come fai a sapere se un personaggio deve essere anti-aliasing? La risposta dipende dai caratteri che si trovano immediatamente sopra, sotto, a sinistra ea destra del personaggio ( non le diagonali ). Ecco un grafico di quando è richiesto l'antialiasing, dove ?e xpuò rappresentare qualsiasi carattere non di spazi bianchi.

 x? ->  d?
 ?      ? 


?x  -> ?b 
 ?      ? 

 ?      ? 
?x  -> ?F 


 ?      ? 
 x? ->  Y?



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

 ?      ? 
 x  ->  V 



?x  -> ?> 



 x? ->  <?



 x  ->  @ 

Input (ed esempio arte ASCII pre-antialiasing)

Innanzitutto, ci saranno due righe di input (a STDIN), un numero H seguito da un numero W. Quindi ci saranno H righe di esattamente W caratteri ciascuna (esclusa la nuova riga). Queste righe seguenti saranno l'arte ASCII che deve essere anti-alias. Ecco un esempio di input (non bello, ma un test):

7
9
  888888 
 888888  
999 98  7
 666666  
  666666 
   6666  
    6    

Output (ed esempio arte anti-aliasing)

Il tuo programma dovrebbe inviare a STDOUT l'arte ASCII (delle stesse dimensioni), che è stata anti-alias. Ecco l'output per l'input sopra. Notare come i caratteri del bordo vengono trattati come spazi bianchi confinanti.

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

Questo potrebbe non sembrare così buono (a causa dello spazio tra le linee nel blocco di codice), sembra migliore con l'arte ASCII più grande e la qualità dipende dall'esatto carattere utilizzato.

Un altro esempio

Ingresso

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

Produzione

   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

Regole, restrizioni e note

Il tuo programma dovrebbe essere scritto solo con caratteri ASCII stampabili, in modo da poter creare arte dai programmi. Oltre a ciò, si applicano le regole standard del code-golf.


Dato che non ci sono ancora risposte, ho cambiato un carattere nella tabella dell'anti-aliasing. _è diventato ;perché funziona meglio.
PhiNotPi

Questa potrebbe essere la mia domanda preferita sul golf in codice di tutti i tempi. Lavorando su 4 diverse fantastiche soluzioni.
captncraig,

Anche se sono confuso. Dici che le diagonali non contano, ma i tuoi diagrammi mostrano tutti punti interrogativi che riempiono le diagonali. Da quello che vedo negli esempi, può essere sicuro guardare solo ai lati, ma mi confondo? Le diagonali contano mai?
captncraig,

No, le diagonali non contano mai. Probabilmente sarà più chiaro se ho rimosso le diagonali dal grafico.
PhiNotPi

Penso che potrebbe esserci un refuso nel tuo esempio; Credo che la colonna di destra dovrebbe avere Y sul bordo interno. Mi è piaciuto trovare la risposta a questa domanda, buona domanda: D
Ed James,

Risposte:


8

Rubino, 180 168 caratteri

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]}

Un'altra implementazione di Ruby che adotta un approccio zip. Puoi vedere il secondo esempio in esecuzione online .

Modifica: usando readlinessalva 12 caratteri.


6

Rubino 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

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

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


1) Le parentesi attorno alla definizione dell'intervallo non sono necessarie. 2) 0..h-1può essere scritto come 0...h. 3) G=[];h.times{G<<gets}può essere scritto come G=readlines, allo stesso modo del codice C #. 4) Dopo il passaggio 3. la variabile h diventa inutile, i valori di h e w vengono usati una sola volta, quindi h=gets.to_i;w=gets.to_i;H=(0..h-1);W=(0..w-1)possono essere scritti come H=0...gets.to_i;W=0...gets.to_i. 5) In questo caso andpuò essere scritto come &&, che non necessita degli spazi intorno. 6) Hai un extra; e hai contato la nuova riga alla fine del file, che non sono necessari. Questo significa 214 caratteri: ideone.com/CiW0l
manatwork

Wow grazie! Sapevo che c'erano miglioramenti da apportare, ma non avrei mai pensato che ce ne fossero così tanti. Avevo provato H=0..gets.to_iquando ho scritto il codice, ma non sembrava funzionare (ovviamente deve essere stato per altri motivi).
Cristian Lupascu,

1
Ancora due punti in cui è possibile ridurre di almeno 7 caratteri: 1) È possibile utilizzare mapinvece di each2) z=->...anziché def z...end.
Howard,

@Howard Grazie, ho applicato mapinvece il eachcambiamento. Per la sintassi lambda, tuttavia, penso che richiederebbe che gli usi di zsiano della forma z.call(args)anziché di z(args), aggiungendo un po 'al conteggio dei caratteri. Per favore fatemi sapere se mi manca qualcosa.
Cristian Lupascu,

@Howard Nevermind, ho appena scoperto cosa mi mancava. Aggiornerò per utilizzare l' []utilizzo di lambda .
Cristian Lupascu,

4

Javascript, 410 caratteri:

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;
}

Originale, 440 caratteri:

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 Ho assunto che le prime due linee di input siano effettivamente irrilevanti e che le dimensioni delle seguenti righe siano corrette. Sto anche calcolando che potrei essere in grado di tagliare alcuni altri caratteri quando avrò la possibilità!


1
Sostituire la dichiarazione di m m={22:"b",28:"d",13:"Y",7:"F",20:";",5:"V",6:">",12:"<",4:"@"}pedice poi convertito di m con parseInt(): m[parseInt(y[d](''),2)]. Ciò riduce la dimensione a 373 caratteri.
arte

3

Python, 259 caratteri

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])

Il programma legge l'input in una singola stringa I(con spazi che separano le linee), comprime un elenco di 5 tuple contenente il carattere e i suoi quattro caratteri circostanti, quindi cerca il carattere risultante usando l'indicizzazione delle stringhe.


3

PHP - 359 330 282 268 257 caratteri

<?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 Non funzionava perché i miei file di test salvati localmente avevano EOL in stile Windows \r\n. Ho aggiornato il mio codice per funzionare con EOL stile unix \n.
Rusty Fausak,

Ok, sembra funzionare ora.
PhiNotPi

2

Python, 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:]))

WC e test sul campione 2, differito con l'output della soluzione Ruby in alto:

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)));}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.