Classificar caracteres por escuridão


38

Seu programa deve ter como entrada uma linha de caracteres, assim:

@+.0

E produza os caracteres classificados pela escuridão, assim:

.+0@

Requisitos:

  • Você deve usar uma fonte monoespaçada para detecção de escuridão.

  • Você deve descobrir quantos pixels cada caractere ocupa. Você deve realmente desenhar o caractere e contar pixels, ou seja, não pode apenas codificar os valores de pixels.

    • Como regra mais concreta: se você trocou as fontes, seu programa ainda deve funcionar. Além disso, seu programa deve poder alternar fontes simplesmente alterando uma variável ou valor ou string no código.
  • Se você usar antialiasing, deverá contar pixels como porcentagens de um pixel totalmente preto. Por exemplo, um rgb(32, 32, 32)pixel contará como 1/8 de um pixel completo. Desconsidere esta regra se seus personagens não tiverem antialias.

  • Depois de contar os pixels, você deve classificar os caracteres pela quantidade de pixels e gerá-los em ordem.

  • Isso é , então o código mais curto em bytes vencerá.


7
Estranhamente, isso também é apropriado para o RPG.se!
precisa saber é o seguinte

1
O que, nenhuma correção para exibir gama no cálculo de escuridão?
Ilmari Karonen

6
Podemos usar uma fonte branca? Se assim for, acho que tenho este embrulhado.
Paul

Respostas:


22

Mathematica, 112 110 108 bytes

Isso ainda pode ser ainda mais jogado. Assume que a sequência está na variável s.

E agora usa uma sintaxe correta para classificar uma lista por outra lista.
Casos de teste de sorte -> "Ah, sim, isso funciona" -> Facepalm
Obrigado pelos olhos afiados, David Carraher.

Atualização: OCR A substituído por Menlo porque percebi que no OSX o nome da família de fontes OCR A é realmente OCR A Std. Então, eu estava classificando uma fonte padrão em vez do negócio real. Menlo também é monoespaçado com a mesma contagem de bytes, portanto, não há ganho ou perda líquida.

Eu coloquei uma exportação CDF hospedado do notebook , para que possa ver o código em ação, se desejar. Ainda estou tentando descobrir como adicionar um pouco de interatividade aos CDFs hospedados na Web, então por enquanto é apenas estático.

c=Characters@s;Last/@Sort[Transpose@{Total[1-#&/@ImageData@Rasterize@Style[#,FontFamily->"Menlo"],3]&/@c,c}]

Saída para s = FromCharacterCode /@ Range[33, 135];com "Courier"

insira a descrição da imagem aqui

Saída para o mesmo, mas com o FontFamily "Monospace":

insira a descrição da imagem aqui

Observe que os resultados finais são mostrados na fonte interna da MM, não na fonte que está sendo classificada. Portanto, você vê as diferenças na fonte escolhida refletidas na classificação. O link CDF mostra ambos, no entanto, para os finalistas.

Código não destruído:

s = FromCharacterCode /@ Range[33, 135];
c = Characters@s;
Last /@ Sort[
    Transpose@{Total[1 - # & /@ 
        ImageData@Rasterize@Style[#, FontFamily -> "Menlo"], 3] & /@ c, c}]

1
Examine esta entrada:"" <> (FromCharacterCode /@ Range[33, 135])
DavidC

Família padrão ou não, as especificações exigidas "seu programa deve poder trocar de fonte simplesmente alterando uma variável". Por causa dos valores de suavização de serrilhado, é possível obter alguns tipos que parecem errados, mas examinarei novamente toda a gama e veremos se há algo errado.
Jonathan Van Matre

1
que linguagem maravilhosa! acabei de descobrir sobre o novo esforço de linguagem de programação da Wolfram outro dia, ansioso por isso.
the0ther

1
Você pode salvar dois bytes alterando Caracteres [] para Caracteres @ e Reverse [] para Reverse @.
Michael Stern

2
Eu não quero postar uma resposta semelhante, mas eu me tentou e ele veio mais curtoStringJoin@SortBy[Characters@"@+.0",ImageData@Binarize@Rasterize@Style[#,FontFamily->"Monospace"]~Total~2&]
swish

25

Bash + ImageMagick: 164 147 148 caracteres

while read -n1 c
do
o=`convert -size 20x15 xc: +antialias -font cour.ttf -draw "text 0,10 '$c'" xpm:-`
o=${o//[^ ]}
a[${#o}]+=$c
done
echo "${a[@]}"

Exemplo de execução:

bash-4.1$ echo -n '@+.0' | bash graysort.sh
. + 0 @

Separadores são inseridos entre grupos de tons de cinza. Caracteres com nível de cinza idêntico não são separados:

bash-4.1$ echo -n 'abcdefghijklmnopqrstuvwxyz' | bash graysort.sh
i cl jortz esv ax u df bgnpq y hk w m

+1 para classificar usando índices de matriz bash em vez desort
Digital Trauma

9

QBasic, 259 bytes

SCREEN 1
DIM a(255)
FOR i = 32 TO 255
    CLS
    PRINT CHR$(i);
    FOR p = 0 TO 64
        a(i) = a(i) + POINT(p MOD 8, p \ 8)
    NEXT p
NEXT i
FOR p = 0 TO 96
    FOR i = 32 TO 255
        IF a(i) = p THEN PRINT CHR$(i);
    NEXT i
NEXT p

Eu fiz isso por diversão, por isso é tecnicamente não compatível com as regras de uma maneira. Não leva uma lista de caracteres, mas imprime todos os caracteres de 32 a 255 e usa-os. Se você realmente deseja ver uma versão que esteja em conformidade com esta regra, informe-me.

Ele também falha em outro detalhe técnico: "Além disso, seu programa deve poder alternar fontes simplesmente alterando uma variável ou valor ou string no código". Não há uma maneira fácil de fazer isso no QBasic. No entanto, é claro que o programa funcionará bem em qualquer página de código de sua escolha.

Por fim, eu poderia espremer alguns caracteres (principalmente espaços em branco que o QBasic IDE insere de maneira útil), mas provavelmente não vale a pena, pois essa resposta não tem chance de ganhar de qualquer maneira.

QBasic classificar caracteres por escuridão


Mais um por fazer isso por diversão!
Jonathan Van Matre

8

DOM do Javascript + Canvas e navegador ( 280 237 235 bytes)

Versão atualizada com sugestões de Fors e escova de dentes nos comentários:

function m(x){a=document.createElement('canvas').getContext('2d');a.font='9px Monaco';a.fillText(x,y=i=0,20);for(;i<3600;)y+=a.getImageData(0,0,30,30).data[i++];return y}alert(s.split('').sort(function(a,b){return m(a)-m(b)}).join(''))

Versão mais legível:

// Scoring function - Calculates darkness for single character
function m(x) {
    a = document.createElement('canvas').getContext('2d');
    a.font = '9px Monaco';
    a.fillText(x, y = i = 0, 20);
    for (; i < 3600;) y += a.getImageData(0, 0, 30, 30).data[i++];
    return y
}
// Assume input is in variable s and alert as output. Comparison function now expression.
alert(s.split('').sort(function (a, b) {
    return m(a) - m(b)
}).join(''))

Talvez possa ser jogado mais.

Eu sou novo neste site, por isso não tenho certeza de como a entrada é normalmente lida para respostas Javascript. Presumo entrada está contido em uma variável chamada s. Caso contrário, atualizarei a resposta e a contagem de caracteres.

JSFiddle da versão atualizada.

JSFiddle da primeira versão .


Eu realmente gosto, no entanto, existem muitas melhorias possíveis aqui. As variáveis ce ssão desnecessárias ( a=document.createElement('canvas').getContext('2d')e y+=a.getImageData(0,0,30,30).data[i]), o elemento não precisa ser anexado, a inicialização zero de ypode ser combinada com a de i( i=y=0), o pós-incremento de ipode ser combinado com a adição de y( for(...;y+=...[i++]);) e o tipo de letra Mônaco é mono-espaçada e tem um nome mais curto que Courier.
Fors

Obrigado! Ainda não sou um jogador experiente, portanto seus comentários ajudam muito. Eu os incorporei ao código agora.
waxwing

As respostas Javascript aqui normalmente leem a entrada prompt(); mas isso também é bom.
Kartik

Você pode remover y=i=0;e alterar a.fillText(x,0,20)para a.fillText(x,y=i=0,20).
Escova de dentes

Obrigado, acrescentou que também! Dois caracteres são dois caracteres!
waxwing

3

PHP, 298 caracteres

Adicionei algumas quebras de linha para que você possa vê-lo em todo o seu hediondo:

<?php
$s=@$_GET[s];$a=array();$v=imagecreate(16,16);$f='imagecolorallocate';
$f($v,0,0,0);for($i=0;$i<strlen($s);$i++){$c=$f($v,$i,0,1);
imagechar($v,5,2,$n=0,$s[$i],$c);for($y=16;$y--;)
for($x=16;$x--;)$n+=($c==imagecolorat($v,$x,$y));
$a[]=ord($s[$i])+($n<<8);}sort($a);foreach($a as $v)echo chr($v);

Este código usa as fontes GD que vêm embutidas no PHP. O segundo argumento de imagechar()seleciona a fonte (números de 1 a 5 são válidos).

Exemplo:

Input:  !@#$%^&*-=WEIX,./'
Output: '-.,^=!/*IE%X#$&@W

Se você inserir o seguinte no topo do código mostrado acima, poderá fornecer a lista de caracteres no seu navegador da web.

<?php
define("FONT_SIZE",5);
if(@$_SERVER['PATH_INFO']=='/a.png') {
  $s = $_GET['s'];
  $im = imagecreate(strlen($s)*(FONT_SIZE+4)+4,FONT_SIZE+12);
  imagecolorallocate($im,255,255,128);
  $c = imagecolorallocate($im,0,0,0);
  imagestring($im,FONT_SIZE,2,0,$s,$c);
  header("Content-Type: image/png");
  imagepng($im);
  imagedestroy($im);
  exit();
}
$me = $_SERVER['PHP_SELF'];
$t1 = $img = "";
if ($t1=htmlspecialchars(@$_GET['s'])) {
  $t2=urlencode($_GET['s']);
  $img="<p><img src=\"$me/a.png?s=$t2\" /></p>";
}
echo <<<END_HTML
<html>
<body>
$img
<form action="$me" method="get">
<input type="text" name="s" size="40" value="$t1" />
<input type="submit" value="Go" />
</form>
END_HTML;
if(!isset($_GET['s'])) exit();
?>

1
se você usar, imagecreatetruecolorpoderá soltar o primeiro alocado e usar o nome da função diretamente no segundo, para -11. []em vez de array(). e foreach($a as$v)funciona bem
Einacio

3

GTB

Esse código tem o código mais difícil que eu já escrevi para uma calculadora. Sem valores de pixel codificados, ele realmente desenha o texto em um gráfico e faz um loop para contar cada pixel.

0→I`_%I<l?_T;1,1,s;_,I,1
C;pT;{0,1,2,3,4,5},{0,1,2}→L1(I
0→I%I<l?_T;1,C;L1(I)>L1,I

Entrada

,O.i

Saída

.,iO

Se isso funcionar, é a melhor resposta até agora. O que é GTB?
slater

@slater Por que você não clica no link e descobre?
Timtech

Obrigado por apontar que o título do seu post é realmente um link.
slater

2
O domínio para obter o software necessário para descriptografar seu compilador está morto . Morto aqui também. Traduzi o código manualmente, para a diversão de testá-lo, mas você parece ter aberto 10 parênteses e fechado apenas um, por isso não tenho certeza de como resolver isso. O compilador na minha cabeça diz: "Erro :: identificador inigualável" :)
Jonathan Van Matre

1
@JonathanVanMatre Não se preocupe; A TI-84 as fecha automaticamente para você.
Timtech 13/03/14

3

Java - 468 450 444

public static void main(String[]a){class c implements Comparable<c>{char d;c(char e){d=e;}public int compareTo(c o){return e(d)>e(o.d)?1:-1;}int e(char f){int a=0,x,y;BufferedImage img=new BufferedImage(99,99,1);img.getGraphics().drawString(""+f,9,80);for(y=0;y<99;y++)for(x=0;x<99;x++)a+=img.getRGB(x,y);return a;}}c[]s=new c[a[0].length()];int i=0;for(char d:a[0].toCharArray())s[i++]=new c(d);Arrays.sort(s);for(c d:s)System.out.print(d.d);}

@+.0abcdefghijklmnopqrstuvwxyz -> .irl+jcvtfxyzsuonkheaqpdb0wgm@

Ungolfed:

    public static void main(String[] a) {
    a = new String[]{"@+.0abcdefghijklmnopqrstuvwxyz"};
    class c implements Comparable<c> {
        char    d;

        c(char e) {
            d = e;
        }

        @Override
        public int compareTo(c o) {
            return e(d) > e(o.d)? 1 : -1;
        }

        int e(char f) {
            int a = 0, x, y;
            BufferedImage img = new BufferedImage(99, 99, 1);
            img.getGraphics().drawString("" + f, 9, 80);
            for (y = 0; y < 99; y++)
                for (x = 0; x < 99; x++)
                    a += img.getRGB(x, y);
            return a;
        }
    }
    c[] s = new c[a[0].length()];
    int i = 0;
    for (char d : a[0].toCharArray())
        s[i++] = new c(d);
    Arrays.sort(s);
    for (c d : s)
        System.out.print(d.d);
}

Dica: evite modificadores públicos ou privados, tanto quanto possível; que salva bytes desnecessários
masterX244

esqueci tudo sobre isso
Mark Jeronimus

@ MarkJeronimus, era dessa maneira que eu iria enfrentá-lo, mas eu queria tentar usar o FontRenderingContext.
Magic Octopus Urn

3

Postscript, 381

Aqui está algo completamente diferente, apenas por diversão. Como a maioria das fontes é vetorial de qualquer maneira, 'contar pixels' é um pouco estranho, não é? Calcular a área da forma do glifo, apesar de estar correta, não é tão fácil. Uma alternativa pode ser a digitalização de um retângulo e a contagem de 'ocorrências' quando um ponto está dentro de uma forma de glifo, e o Postscript possui operadores para esse tipo de verificação. No entanto, é verdade que a digitalização e o teste de insidiosidade são apenas uma maneira estranha de contar pixels.

(%stdin)(r)file token pop/Courier 99 selectfont[1 index length{0}repeat]0 1 99{0 1 99{0 1 5 index length 1 sub{newpath 9 19 moveto 3 copy 7 index exch 1 getinterval false charpath infill{3 index exch 2 copy get 1 add put}{pop}ifelse}for pop}for pop}for 0 1 99 dup mul{0 1 3 index length 1 sub{dup 3 index exch get 2 index eq{3 index exch 1 getinterval print}{pop}ifelse}for pop}for

.

(%stdin) (r) file token pop
/Courier 99 selectfont
%/DejaVuSansMono 99 selectfont
%/UbuntuMono-Regular 99 selectfont
[ 1 index length {0} repeat ]   % str []
0 1 99 {
    0 1 99 {
        0 1 5 index length 1 sub {
            newpath 
            9 19 moveto
            3 copy              % str [] n m i n m i
            7 index exch        % str [] n m i n m str i
            1 getinterval       % str [] n m i n m s
            false charpath      % str [] n m i n m
            infill              % str [] n m i bool
            {3 index exch 2 copy get 1 add put} {pop} ifelse
        } for
        pop
    } for
    pop
} for
% un-comment next line to print number of 'hits' for each glyph
%
% dup {=} forall
%
% next is 'lazy sort'
0 1 99 dup mul {                % str [] i
    0 1 3 index length 1 sub {  % str [] i j
        dup 3 index exch        % str [] i j [] j
        get 2 index eq          % str [] i j bool
        {3 index exch 1 getinterval print} {pop} ifelse
    } for
    pop
} for
()=

E aqui estão os resultados para três fontes diferentes (seleção das quais podem ser não comentadas, acima):

$ echo '(.-?@AByz01)' | gs -q -dBATCH d.ps
.-?1z0yA@B
$ echo '(.-?@AByz01)' | gs -q -dBATCH d.ps
.-?z1yA0B@
$ echo '(.-?@AByz01)' | gs -q -dBATCH d.ps
.-?1zyA0B@

Pixels contando ... interseções pixel de contagem ... tomate .... tomahto ....
Jonathan Van Matre

2

Perl (com GD) (159)

use GD;sub i{$i=new GD'Image 5,8;$B=colorExact$i 9,9,9;colorExact$i 0,0,0;char$i gdTinyFont,0,0,@_,1;$_=unpack"B*",wbmp$i 0;y/0//c}print+sort{i($a)-i($b)}@ARGV

uso:

> perl dark.pl 1 2 3 @ # . , : ~ $ M i I s S
.,~:i13Is2S$M@#

editar: reduzido para 159 caracteres


2

Java, 584

Uau ... Esta não era uma boa linguagem para fazer isso.

import java.awt.geom.*;import java.util.*;class F{static void n(final String f,List<Character> s){Collections.sort(s,new Comparator<Character>(){public int compare(Character a,Character b){return d(f,""+a) - d(f,""+b);}});}static int d(String f,String s){int i=0;PathIterator p=new java.awt.Font(f,0,12).createGlyphVector(((java.awt.Graphics2D)new java.awt.image.BufferedImage(8,8,2).getGraphics()).getFontRenderContext(),s).getGlyphOutline(0).getPathIterator(AffineTransform.getRotateInstance(0.0, 0.0));while(!p.isDone()){i+=p.currentSegment(new double[99])/2;p.next();}return i;}}

Uso:

import java.awt.geom.*;
import java.util.*;
public class F {
    public static void main(String[]args){
        List<Character> s = new ArrayList<Character>(0);
        s.add('@');
        s.add('+');
        s.add('.');
        s.add('0');
        n("Calibri", s);
        System.out.println(s);
    }
    static void n(final String f,List<Character> s){
        Collections.sort(s,new Comparator<Character>(){
            public int compare(Character a,Character b){
                return d(f,""+a) - d(f,""+b);
            }
        });
    }

    static int d(String f,String s){
        int i=0;
        PathIterator p=new java.awt.Font(f,0,12).createGlyphVector(((java.awt.Graphics2D)new java.awt.image.BufferedImage(8,8,2).getGraphics()).getFontRenderContext(),s).getGlyphOutline(0).getPathIterator(AffineTransform.getRotateInstance(0.0, 0.0));
        while(!p.isDone()){
            i+=p.currentSegment(new double[99])/2;
            p.next();
        }
        return i;
    }
}

Essa configuração resulta em:

[., +, 0, @]

A única linha aqui que precisa de explicação:

PathIterator p=new java.awt.Font(f,0,12).createGlyphVector(((java.awt.Graphics2D)new java.awt.image.BufferedImage(8,8,2).getGraphics()).getFontRenderContext(),s).getGlyphOutline(0).getPathIterator(AffineTransform.getRotateInstance(0.0, 0.0));
  • Inicialize o objeto de fonte 12pt com a fonte passada.
  • Crie um novo objeto BufferedImage para criar um objeto Graphics2D vinculado a um GraphicsContext.
  • Obtenha o contexto de renderização da fonte do contexto de gráficos 2D para a sequência s.
  • Obtenha o primeiro glifo (somente glifo) na string.
  • Obtenha o iterador de caminho (lista de pontos).

Então esta peça final reúne ...

while(!p.isDone()){
    i+=p.currentSegment(new double[99])/2;
    p.next();
}

Iterando todos os pontos e somando a contagem de pontos. Essas informações de densidade são passadas de volta para o comparador e são usadas para classificação.


1

R, 195 caracteres

A=strsplit(scan(,""),"")[[1]];cat(A[order(sapply(A,function(x){png('a',a='none',fa='monospace');frame();text(0,0,x);dev.off();sum(apply(png::readPNG('a'),c(1,2),function(x)any(x!=1)))}))],sep="")

Recuado com comentários:

A=strsplit(scan(,""),"")[[1]] #Take characters as strings and split into single chars
cat(A[order(sapply(A,function(x){ #Apply the following function to each char and order accordingly
                 png('a',a='none',fa='monospace'); #Open empty png without antialiasing and with monospace font
                 frame(); #create empty plot
                 text(0,0,x); #add the char as text to the plot
                 dev.off(); #close png device
                 sum(apply(png::readPNG('a'), #read it back as rbga 3d matrix
                           c(1,2), #check every layer (R, G, B, A)
                           function(x)any(x!=1))) #if any are not 1, send TRUE
                 }))], #Sum all TRUEs
    sep="") #Prints to output

Exemplo:

> A=strsplit(scan(,""),"")[[1]];cat(A[order(sapply(A,function(x){png('a',a='none',fa='monospace');frame();text(0,0,x);dev.off();sum(apply(png::readPNG('a'),c(1,2),function(x)any(x!=1)))}))],sep="")
1: @+.0
2: 
Read 1 item
.+0@
> A=strsplit(scan(,""),"")[[1]];cat(A[order(sapply(A,function(x){png('a',a='none',fa='monospace');frame();text(0,0,x);dev.off();sum(apply(png::readPNG('a'),c(1,2),function(x)any(x!=1)))}))],sep="")
1: 1234567890
2: 
Read 1 item
1723450689

Como a gestão de fontes nos gráficos R depende da plataforma, não posso garantir que funcione no PC, mas no Mac (OS X 10.7.5, R 2.14.2).


1

SmileBASIC, 179 176 173 bytes

INPUT S$DIM Q$[0],A[0],Z[0]WHILE""<S$C$=POP(S$)GCLS
PUSH Q$,C$
GPUTCHR.,0,C$
GSAVE.,0,8,8,A,0S=0FOR I=0TO 63S=S+A[I]NEXT
PUSH Z,S
WEND
RSORT Z,Q$
WHILE LEN(Q$)?POP(Q$);
WEND

Usa a fonte atualmente carregada. As fontes podem ser carregadas LOAD"GRPF:filename".

Código mais legível:

INPUT STRING$
DIM CHARS$[0],PIXELS[0],SIZES[0]
WHILE STRING$>""
 CHAR$=POP(STRING$)
 PUSH CHARS$,CHAR$
 GCLS
 GPUTCHR 0,0,CHAR$
 GSAVE 0,0,8,8,PIXELS
 SIZE=0
 FOR I=0 TO 63
  INC SIZE,PIXELS[I]
 NEXT
 PUSH SIZES,SIZE
WEND
RSORT SIZES,CHARS$
WHILE LEN(CHARS$)
 PRINT POP(CHARS$);
WEND

0

PHP - 485

Demo:

$ php pcg-23362.php "@+.0"
.+0@

Código:

<?php $f='x.ttf';$d=array();foreach(str_split($argv[1]) as$_){$B=imagettfbbox(50,0,$f,$_);$w=abs($B[4]-$B[0]);$h=abs($B[5]-$B[1]);$im=imagecreate($w,$h);imagecolorallocate($im,255,255,255);imagettftext($im,50,0,0,$h-$B[1],imagecolorallocate($im,0,0,0),$f,$_);$b=$w*$h;for($x=0;$x<$w;$x++)for($y=0;$y<$h;$y++){$z=imagecolorsforindex($im,imagecolorat($im,$x,$y));$color=$z['red']*$z['green']*$z['blue'];$b-=$color/0x1000000;}$d[$_]=$b / ($w * $h);}asort($d);echo implode(array_keys($d));

Ei, me envie uma cópia do X.TTF ... a fonte mais curto que eu tenho é OCR A. ;-D
Jonathan Van Matre

0

Python + freetype-py: 147

import sys,freetype as F;f=F.Face('m.ttf');f.set_char_size(99);print(sorted([(f.load_char(c)or sum(f.glyph.bitmap.buffer),c)for c in raw_input()]))
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.