Trier les caractères par obscurité


38

Votre programme doit prendre en entrée une ligne de caractères, comme ceci:

@+.0

Et affichez les caractères triés par ordre d'obscurité, comme ceci:

.+0@

Exigences:

  • Vous devez utiliser une police à espacement fixe pour détecter l'obscurité.

  • Vous devez savoir combien de pixels chaque personnage occupe. Vous devez réellement dessiner le caractère et compter les pixels, c’est-à-dire que vous ne pouvez pas coder en dur les quantités de pixels.

    • En règle plus concrète: si vous changiez de police, votre programme devrait toujours fonctionner. De plus, votre programme devrait pouvoir changer de police en changeant simplement une variable, une valeur ou une chaîne dans le code.
  • Si vous utilisez l'antialiasing, vous devez compter les pixels en pourcentage d'un pixel entièrement noir. Par exemple, un rgb(32, 32, 32)pixel comptera pour 1/8 d'un pixel complet. Ne tenez pas compte de cette règle si vos personnages ne sont pas anti-aliasés.

  • Après avoir compté les pixels, vous devez trier les caractères en fonction du nombre de pixels et les afficher dans l’ordre.

  • C'est du , donc le code le plus court en octets va gagner.


7
Curieusement, cela convient également à RPG.se!
CorsiKa

1
Quoi, pas de correction pour l'affichage gamma dans le calcul de l'obscurité?
Ilmari Karonen

6
Peut-on utiliser une police blanche? Si oui, je pense que celui-ci est bouclé.
Paul

Réponses:


22

Mathematica, 112 110 108 octets

Cela peut encore probablement être joué au golf. Suppose que la chaîne est dans la variable s.

Et utilise maintenant une syntaxe correcte pour trier une liste par une autre liste.
Des cas de test chanceux -> "Oh oui, ça marche" -> Facepalm
Merci pour les yeux perçants, David Carraher.

Mise à jour: OCR A remplacé par Menlo car je me suis rendu compte que, sur OSX, le nom de famille de la police OCR A était en réalité OCR A Std. Donc, je triais une police par défaut au lieu de la vraie affaire. Menlo est également monospaced avec le même nombre d'octets, donc pas de gain net ni de perte.

J'ai mis en place une exportation CDF hébergée du bloc-notes afin que vous puissiez voir le code en action si vous le souhaitez. Je ne sais toujours pas comment ajouter une certaine interactivité aux CDF hébergés sur le Web, donc, pour l'instant, ce n'est que statique.

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

Sortie pour s = FromCharacterCode /@ Range[33, 135];avec "Courier"

enter image description here

Sortie identique, mais avec FontFamily "Monospace":

enter image description here

Notez que les résultats finaux sont affichés dans la police interne de MM et non dans la police en cours de tri. Par conséquent, vous voyez les différences dans la police choisie reflétées dans le tri. Le lien CDF montre les deux, cependant, pour les complétistes.

Code non golfé:

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

1
Examinez cette entrée:"" <> (FromCharacterCode /@ Range[33, 135])
DavidC

Famille par défaut ou non, les spécifications requises "votre programme devrait pouvoir changer de police en changeant simplement une variable". En raison des valeurs d'anti-aliasing, il est possible d'obtenir certaines sortes qui semblent fausses, mais j'examinerai à nouveau la gamme complète pour voir si quelque chose ne va pas.
Jonathan Van Matre

1
quelle langue géniale! Je viens d’apprendre le nouvel effort de Wolfram en matière de langage de programmation, impatient de le faire.
07

1
Vous pouvez enregistrer deux octets en modifiant Caractères [] en Caractères @ et Inverser [] en Inverse @.
Michael Stern

2
Je ne veux pas poster une réponse similaire, mais j'ai essayé moi-même et il s'est StringJoin@SortBy[Characters@"@+.0",ImageData@Binarize@Rasterize@Style[#,FontFamily->"Monospace"]~Total~2&]
avéré

25

Bash + ImageMagick: 164 147 148 caractères

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[@]}"

Échantillon échantillon:

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

Des séparateurs sont insérés entre les groupes de gris. Les caractères avec un niveau de gris identique ne sont pas séparés:

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

+1 pour le tri en utilisant les indices de tableau bash au lieu desort
Digital Trauma

9

QBasic, 259 octets

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

Je l’ai fait pour le plaisir, c’est donc techniquement non conforme aux règles d’une manière. Il ne prend pas une liste de caractères, mais affiche tous les caractères de 32 à 255 et l’utilise à la place. Si vous voulez vraiment voir une version qui respecte cette règle, merci de me le dire.

Cela échoue également avec un autre détail technique: "En outre, votre programme devrait pouvoir changer de police simplement en modifiant une variable, une valeur ou une chaîne dans le code." Il n'y a pas de moyen facile de faire cela depuis QBasic. Cependant, le programme fonctionnera bien avec n'importe quelle page de codes de votre choix.

Enfin, je pourrais supprimer quelques caractères (principalement des espaces que l'EDI QBasic insère utilement), mais cela ne vaut probablement pas la peine, car cette réponse n'a aucune chance de gagner de toute façon.

QBasic trie les personnages par obscurité


Plus un pour le faire pour le plaisir!
Jonathan Van Matre

8

Javascript + Canvas et navigateur DOM ( 280 237 235 octets)

Version mise à jour avec des suggestions de Fors et une brosse à dents dans les commentaires:

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(''))

Version plus lisible:

// 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(''))

Peut-être peut-être plus joué au golf.

Je suis nouveau sur ce site, je ne suis donc pas sûr de savoir comment l'entrée est lue normalement pour les réponses Javascript. Je suppose que l'entrée est contenue dans une variable nommée s. Si cela ne va pas, je mettrai à jour la réponse et le nombre de caractères.

JSFiddle de la version mise à jour.

JSFiddle de la première version .


J'aime vraiment beaucoup, mais il y a beaucoup d'améliorations possibles ici. Les variables cet ssont inutiles ( a=document.createElement('canvas').getContext('2d')et y+=a.getImageData(0,0,30,30).data[i]), l'élément n'a pas besoin d'être ajouté, l'initialisation de zéro ypeut être combinée avec celle de i( i=y=0), la post-incrémentation de ipeut être combinée avec l'ajout de y( for(...;y+=...[i++]);) et la police de caractères Monaco est mono-espacé et porte un nom plus court que Courier.
Fors

Merci! Je ne suis pas encore un golfeur chevronné, alors vos commentaires aident beaucoup. Je les ai incorporés dans le code maintenant.
waxwing

Les réponses Javascript ici lisent normalement les entrées prompt(); mais c'est aussi bien.
Kartik

Vous pouvez supprimer y=i=0;et changer a.fillText(x,0,20)pour a.fillText(x,y=i=0,20).
Brosse à dents

Merci, ajouté ça aussi! Deux personnages sont deux personnages!
waxwing

3

PHP, 298 caractères

J'ai ajouté quelques sauts de ligne pour que vous puissiez le voir dans toute son horreur:

<?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);

Ce code utilise les polices GD intégrées à PHP. Le deuxième argument de imagechar()sélectionne la police (les nombres de 1 à 5 sont valides).

Exemple:

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

Si vous insérez ce qui suit en haut du code indiqué ci-dessus, vous pourrez alors fournir la liste des caractères dans votre navigateur 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
si vous l'utilisez, imagecreatetruecolorvous pouvez supprimer le premier allocation et utiliser le nom de la fonction directement sur le second, pour -11. []au lieu de array(). et foreach($a as$v)fonctionne aussi bien
Einacio

3

GTB

Ceci a le code pour être le deuxième code le plus dur que j'ai jamais écrit pour une calculatrice. Aucune valeur de pixel codée en dur, elle dessine le texte sur un graphique et effectue une boucle pour compter chaque 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

Contribution

,O.i

Sortie

.,iO

Si cela fonctionne, c'est la meilleure réponse jusqu'à présent. Quel est le GTB?
slater

@slater Pourquoi ne cliquez-vous pas sur le lien pour le savoir?
Timtech

Merci de signaler que le titre de votre message est bien un lien.
slater

2
Le domaine pour obtenir le logiciel nécessaire pour décrypter votre compilateur est mort . Morte ici aussi. J'ai traduit le code à la main pour le plaisir de le tester, mais vous semblez avoir ouvert 10 paragraphes et n'en avoir fermé qu'un, alors je ne sais pas comment résoudre ce problème. Le compilateur dans ma tête dit: "Erreur :: identificateur sans équivalent" :)
Jonathan Van Matre

1
@ JonathanVanMatre Ne vous inquiétez pas; La TI-84 les ferme automatiquement pour vous.
Timtech

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

Astuce: évitez autant que possible les modificateurs publics ou privés; qui sauve des octets inutiles
masterX244

a oublié tout ça
Mark Jeronimus

@ MarkJeronimus, c’est ainsi que j’allais l’empêcher, mais je voulais essayer d’utiliser FontRenderingContext.
Urne magique Octopus le

3

Postscript, 381

Voici quelque chose de complètement différent, juste pour le plaisir. Comme la plupart des polices sont de toute façon vectorielles, «compter les pixels» est un peu étrange, n'est-ce pas. Calculer la surface des glyphes, tout en étant correct, n’est pas si facile. Une autre solution consiste à numériser un rectangle et à compter les occurrences lorsqu'un point se trouve à l'intérieur d'une forme de glyphe. Postscript dispose d'opérateurs pour ce type de vérification. Certes, la numérisation et les tests d'insiduité ne sont qu'un étrange moyen de compter les 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
()=

Et voici les résultats pour 3 polices différentes (dont la sélection peut être non commentée, ci-dessus):

$ 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@

Comptage des pixels ... Comptage des intersections de pixels ... Tomate .... Tomahto ....
Jonathan Van Matre

2

Perl (avec 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

usage:

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

edit: raccourci à 159 caractères


2

Java, 584

Wow ... Ce n'était pas une bonne langue pour faire ça.

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

Usage:

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

Cette configuration entraîne:

[., +, 0, @]

La seule ligne qui nécessite une explication:

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));
  • Initialisez l'objet police 12pt avec la police transmise.
  • Créez un nouvel objet BufferedImage pour créer un objet Graphics2D lié à un GraphicsContext.
  • Obtenez le contexte de rendu de police du contexte graphique 2D pour la chaîne s.
  • Obtenez le premier glyphe (uniquement glyphe) dans la chaîne.
  • Récupère l'itérateur de chemin (liste de points).

Ensuite, cette dernière pièce le rassemble ...

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

En parcourant tous les points et en additionnant le nombre de points. Cette information de densité est renvoyée au comparateur et est utilisée pour le tri.


1

R, 195 caractères

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="")

Indenté avec commentaires:

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

Exemple:

> 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

La gestion des polices dans les graphes R étant dépendante de la plate-forme, je ne peux pas garantir son fonctionnement sur PC, mais sur Mac (OS X 10.7.5, R 2.14.2).


1

SmileBASIC, 179 176 173 octets

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

Utilise la police actuellement chargée. Les polices peuvent être chargées avec LOAD"GRPF:filename".

Code plus lisible:

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

Démo:

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

Code:

<?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));

Salut, envoie-moi une copie de X.TTF ... la police la plus courte que j'ai est 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()]))
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.