Dessiner des hexagones ASCII concentriques

15

Écrivez le programme le plus court possible qui accepte un ensemble d'entiers positifs distincts et génère un rendu ASCII d' hexagones concentriques avec ces longueurs latérales, à partir de barres obliques, de soulignements, d'espaces et de nouvelles lignes.

Le programme le plus court en octets compté par https://mothereff.in/byte-counter gagne.

Exemples

(Ils sont plus beaux avec moins d'espacement des lignes.)

Si l'entrée est 1la sortie doit être l'hexagone de longueur latérale 1:

 __ 
/  \
\__/

Notez que deux traits de soulignement sont utilisés pour le haut et le bas de l'hexagone afin qu'il soit mieux proportionné.

En général, l'hexagone de taille N contient N barres obliques de chaque côté incliné et 2 * N traits de soulignement en haut et en bas.

Si l'entrée est 1 2la sortie doit être les hexagones concentriques de longueur latérale 1 et 2:

  ____
 / __ \
/ /  \ \
\ \__/ /
 \____/

Si l'entrée est 1 3la sortie doit être:

   ______
  /      \
 /   __   \
/   /  \   \
\   \__/   /
 \        /
  \______/

Si l'entrée est 1 3 2la sortie doit être:

   ______
  / ____ \
 / / __ \ \
/ / /  \ \ \
\ \ \__/ / /
 \ \____/ /
  \______/

etc.

Règles d'E / S

L'entrée doit provenir de la ligne de commande ou de stdin mais peut être dans le format le plus pratique.

Par exemple, vous pourriez donner à chaque numéro comme un argument de ligne de commande: > myprogram 1 3 2, ou vous pouvez demander à l'utilisateur d'entrer les numéros comme une liste préformaté: [1, 3, 2].

La sortie doit aller vers stdout ou l'équivalent le plus proche de votre langue.

Règles supplémentaires

  • L'entrée sera toujours un ensemble d'entiers positifs distincts, pas nécessairement dans n'importe quel ordre .
  • La sortie doit ...
    • ne pas contenir de caractères en plus /\ _et des nouvelles lignes.
    • n'ont pas d'espaces de fin ou d'espaces de début inutiles.
    • ne doit pas contenir de retour à la ligne superflu mais peut avoir un retour à la ligne facultatif .
  • Si rien n'est entré, rien ne sort (sauf éventuellement une nouvelle ligne).
  • Si cela vous aide, vous pouvez supposer que les entiers d'entrée sont inférieurs à 2 16 .
Loisirs de Calvin
la source
Le fait-il 1référence à l'hexagone le plus intérieur ou le plus extérieur?
NinjaBearMonkey
@hsl Le 1(ou n'importe quel nombre) fait référence à l'hexagone avec une longueur de côté de 1. (Avec la mise en garde que 1 barre oblique = 2 traits de soulignement.) Donc, 1se référera toujours à l'hexagone le plus intérieur.
Calvin's Hobbies

Réponses:

4

CJAM, 148 116 109 octets

Cela a pris beaucoup plus de temps que prévu. À l'origine, je voulais simplement construire de manière itérative le quadrant supérieur gauche, comme dans les défis de diamant, puis retirer le reste de la mise en miroir. Mais je n'ai pas remarqué que les traits de soulignement n'obéissent pas à la symétrie miroir entre la moitié supérieure et inférieure. J'ai donc dû refaire la majeure partie de cela, pour générer la moitié droite de manière itérative, puis ne refléter qu'une seule fois (vers la gauche).

S]2[l~]:(f#:+2bW%{_,2/~:T;{IT):T1<'\'/?S?S++}%__,2/=,2/I'_S?*_S+a@+\I'/S?S++a+}fI{)T)2*2$,-*1$W%"\/"_W%er@N}/

Testez-le ici.

Un exemple de Fibonacci:

8 3 1 5 2
        ________________
       /                \
      /                  \
     /     __________     \
    /     /          \     \
   /     /   ______   \     \
  /     /   / ____ \   \     \
 /     /   / / __ \ \   \     \
/     /   / / /  \ \ \   \     \
\     \   \ \ \__/ / /   /     /
 \     \   \ \____/ /   /     /
  \     \   \______/   /     /
   \     \            /     /
    \     \__________/     /
     \                    /
      \                  /
       \________________/

Explication:

Comme indiqué en haut, je commence par construire la moitié droite de manière itérative. Autrement dit, au départ, je n'ai qu'un seul espace dans la grille, puis pour chaque anneau possible, j'entoure la grille existante dans des espaces ou un nouveau semi-hexagone.

Une fois cela fait, je mets en miroir chaque ligne vers la gauche et je la remplis d'espaces de tête pour un alignement correct. Voici une ventilation du code:

"Prepare the input and the grid:";
S]2[l~]:(f#:+2bW%
S]                "Push string with a space and wrap it in an array. This is the grid.";
  2               "Push a 2 for future use.";
   [l~]           "Read and evaluate the input, wrap it in an array.";
       :(         "Decrement each number by 1.";
         f#       "Map each number i to 2^i.";
           :+     "Sum them all up.";
             2b   "Get the base two representation.";
               W% "Reverse the array.":
"At this point, the stack has the proto-grid at the bottom, and an array of 1s and
 0s on top, which indicates for each hexagon if it's present or not.";

"Next is a for loop, which runs the block for each of those 0s and 1s, storing the
 actual value in I. This block adds the next semi-hexagon or spaces.";
{ ... }fI

"First, append two characters to all existing lines:";
_,2/~:T;{IT):T1<'\'/?S?S++}%
_                            "Duplicate the previous grid.";
 ,2/                         "Get its length, integer-divide by 2.";
    ~:T;                     "Get the bitwise complement and store it in T. Discard it.";
        {                 }% "Map this block onto each line of the grid.";
         I                   "Push the current hexagon flag for future use.";
          T):T               "Push T, increment, store the new value.";
              1<'\'/?        "If T is less than 1, push \, else push /.";
                     S?      "If the current flag is 0, replace by a space.";
                       S++   "Append a space and add it to the current line.";

"So for hexagons this appends '\ ' to the top half and '/ ' to the bottom half.
 For empty rings, it appends '  ' to all lines.";

"Now add a new line to the top and the bottom:"    
__,2/=,2/I'_S?*_S+a@+\I'/S?S++a+
__                               "Get two copies of the grid.";
  ,2/                            "Get its length, integer-divide by 2.";
     =                           "Get that line - this is always the middle line.";
      ,2/                        "Get ITS length, integer'divide by 2.";
         I'_S?*                  "Get a string of that many _ or spaces depending on the 
                                  current flag.";
               _S+               "Duplicate and a space.";
                  a@+            "Wrap in an array, pull up the grid, and prepend the line.";
                     \           "Swap with the other copy.";
                      I'/S?      "Choose between / and a space depending on the flag.";
                           S++   "Append a space, and add both characters to the line.";
                              a+ "Wrap in an array, and append line to the grid.";

"This is all. Rinse and repeat for all rings. The result will look something like this:

_____ 
     \ 
___   \ 
__ \   \ 
_ \ \   \ 
 \ \ \   \ 
_/ / /   / 
__/ /   / 
___/   / 
      / 
_____/ 

Note that there are still trailing spaces.";

"Finish up all lines. These will not be joined together any more, but simply left
 on the stack in pieces to printed out back-to-back at the end of the program.
 The following runs the given block for each line:";
{ ... } /

"This generates the necessary indentation, then mirrors the lines and puts them
 in the right order:"
)T)2*2$,-*\_W%"\/"_W%er\N
)                         "Slice off that trailing space, but leave it on the stack.";
 T                        "Remember T? That still has something like the the size of
                           the grid from the last iteration. In fact it's N-1, where
                           N is the largest visible hexagon. We can use that to figure
                           out how many spaces we need.";
  )2*                     "Increment and double.";
     2$                   "Copy the current line.";
       ,-                 "Subtract its length from 2*N.";
         *                "Repeat the space that often. This is our indentation.";
          \_              "Swap with the line and duplicate.";
            W%            "Reverse the line.";
              "\/"_W%er   "Replace slashes with backslashes and vice versa.";
                       \  "Swap with the original line.";
                        N "Push a line break.";
Martin Ender
la source
5

Python - 251, 240, 239 228

l=input()+[0];m=max(l);A=abs;R=range
for j in R(2*m+1):print''.join([[' \\'[(A(j-i+m-1)/2.in l)*(2*m-i)/(j-m-.5)>1],'/'][(A(3*m-i-j)/2.in l)*(i-m-j+.5)/(j-.5-m)>0],'_'][(A(m-j)in l)*(A(2*m-i-.5)<A(m-j))]for i in R(4*m)).rstrip()

Approche alternative (251):

l=input()+[0]
l.sort()
m=max(l)
M=2*m
s=[[' ']*m*4for j in' '*(M+1)]
for i in l:
 I=2*i;s[m-i][M-i:M+i]=s[m+i][M-i:M+i]='_'*I
 for k in range(i):K=k+1;s[m-k][M-I+k]=s[m+K][M+I-K]='/';s[m-k][M+I-K]=s[m+K][M-I+k]='\\'
for t in s:print''.join(t).rstrip()
Falko
la source
3

APL (222 octets en UTF-8)

(et 133 caractères)

Étant donné que cette question demande spécifiquement la quantité d'octets dans la représentation UTF8, j'ai dû en fait ungolf un peu pour qu'il soit plus long mais sa représentation UTF8 est plus courte. (En particulier, le caractère de l'opérateur de trajet est de trois octets alors qu'il ()n'est que de deux, de sorte que l'optimalisation ne fonctionne plus et rend également l'affectation très coûteuse.)

{⎕←(~⌽∧\⌽⍵=' ')/⍵}¨↓⊃{⍵{⍺=' ':⍵⋄⍺}¨K↑(-.5×(K←⍴⍵)+⍴⍺)↑⍺}/{Z⍪⌽⊖Z←↑(⊂(⍵/' '),(2×⍵)/'-'),⍵{((-⍵)↑'/'),((2 4-.×⍵⍺)/' '),'\'}¨⌽⍳⍵}¨N[⍋N←,⎕]

Version précédente, qui est plus courte en caractères (124) mais utilise plus d'octets lorsqu'elle est représentée en UTF-8 (230, ce qui la placerait en deuxième position):

M←' '⋄{⎕←⍵/⍨~⌽∧\⌽⍵=M}¨↓⊃{⍵{⍺=M:⍵⋄⍺}¨K↑⍺↑⍨-.5×(K←⍴⍵)+⍴⍺}/{Z⍪⊖⌽Z←↑(⊂(⍵/M),'-'/⍨2×⍵),⍵{('/'↑⍨-⍵),'\',⍨M/⍨2 4-.×⍵⍺}¨⌽⍳⍵}¨N[⍋N←,⎕]

Tester:

      {⎕←(~⌽∧\⌽⍵=' ')/⍵}¨↓⊃{⍵{⍺=' ':⍵⋄⍺}¨K↑(-.5×(K←⍴⍵)+⍴⍺)↑⍺}/{Z⍪⌽⊖Z←↑(⊂(⍵/' '),(2×⍵)/'-'),⍵{((-⍵)↑'/'),((2 4-.×⍵⍺)/' '),'\'}¨⌽⍳⍵}¨N[⍋N←,⎕]
⎕:
      3 1 5 2
     ----------
    /          \
   /   ------   \
  /   / ---- \   \
 /   / / -- \ \   \
/   / / /  \ \ \   \
\   \ \ \  / / /   /
 \   \ \ -- / /   /
  \   \ ---- /   /
   \   ------   /
    \          /
     ----------
marinus
la source
Cela ne semble pas répondre aux spécifications des côtés supérieur et inférieur (ils devraient être des traits de soulignement, pas des tirets) et par conséquent être décalé d'une ligne pour les côtés inférieurs.
Martin Ender
1

Perl 5, 352 (349 octets + 3 pour les anEdrapeaux)

Cela pourrait probablement être joué beaucoup plus.

@b=sort{$a>$b}@F;map{$_<$j||($j=$_)}@b;$k=++$j;for(;$j--;){$z=$"x$j;for($e=$k;--$e>$j;){$z.=$e~~@b?'/ ':'  '} $z.=($j~~@b?'_':$")x(2*$j);$z.=$_~~@b?' \\':'  'for($j+1..$k-1);say$z}for(0..$k-2){$z=$"x$_;for($e=$k;--$e>$_;){$z.=($e-$k+1?$":'').($e~~@b?'\\':$")}$z.=(($_+1)~~@b?'_':$")x(2*$_+2);$z.=($_~~@b?'/':$").($_-$k+1?$":'')for($_+1..$k-1);say$z}

Non golfé:

# sort list of side lengths 
@b=sort{$a>$b}@F; 
# set $k and $j to max side length + 1
map{$_<$j||($j=$_)}@b;$k=++$j;
for(;$j--;){
  $z=$"x$j;
  for($e=$k;--$e>$j;){$z.=$e~~@b?'/ ':'  '}
  $z.=($j~~@b?'_':$")x(2*$j);
  $z.=$_~~@b?' \\':'  'for($j+1..$k-1);
  say$z
}
for(0..$k-2){
  $z=$"x$_;
  for($e=$k;--$e>$_;){$z.=($e-$k+1?$":'').($e~~@b?'\\':$")}
  $z.=(($_+1)~~@b?'_':$")x(2*$_+2);
  $z.=($_~~@b?'/':$").($_-$k+1?$":'')for($_+1..$k-1);
  say$z 
}

Exemple ( 1 5 3 14):

              ____________________________
             /                            \
            /                              \
           /                                \
          /                                  \
         /                                    \
        /                                      \
       /                                        \
      /                                          \
     /                 __________                 \
    /                 /          \                 \
   /                 /   ______   \                 \
  /                 /   /      \   \                 \
 /                 /   /   __   \   \                 \
/                 /   /   /  \   \   \                 \
\                 \   \   \__/   /   /                 /
 \                 \   \        /   /                 /
  \                 \   \______/   /                 /
   \                 \            /                 /
    \                 \__________/                 /
     \                                            /
      \                                          /
       \                                        /
        \                                      /
         \                                    /
          \                                  /
           \                                /
            \                              /
             \____________________________/
es1024
la source
1

C # - 388 316 octets

Edit: modification de la façon dont il évite d'imprimer les espaces de fin et ajout de LINQ

Programme simple qui prend des arguments de ligne de commande. Il parcourt tous les caractères possibles dans chaque ligne d'un rectangle défini par la dimension hexagonale maximale et l'ajoute à la ligne actuelle, avant de couper les lignes et de les imprimer successivement (il produit la nouvelle ligne facultative de fin).

Code golf:

using System.Linq;class P{static void Main(string[]A){var I=A.Select(int.Parse);int m=I.Max(),i,j,y,x;for(j=m+1;j-->-m;){var r="";for(i=-2*m-1;++i<2*m-(y=j<0?-j-1:j);)r+="/\\_- "[(x=i<0?-i-1:i)>y&(x+=y)%2>0&x/2<m&&I.Contains(x/2+1)?(i^j)&1:x-y<(y=j<0?-j:j)&y<=m&I.Contains(y)?j<0?2:3:4];System.Console.WriteLine(r);}}}

Code non golfé:

using System.Linq; // all important

class P
{
    static void Main(string[]A)
    {
        var I=A.Select(int.Parse); // create int array

        for(int m=I.Max(),j=m+1,i,y,x;j-->-m;) // for each line...
        {
            var r=""; // current line

            for(i=-2*m-1;++i<2*m-(y=j<0?-j-1:j);) // for each char...
                r+="/\\_- "[// append something to the current line
                (x=i<0?-i-1:i)>y&(x+=y)%2>0&x/2<m&&I.Contains(x/2+1)?
                    (i^j)&1: // slashes as appropriate - I can't work out why this bit works, but it seems to
                x-y<(y=j<0?-j:j)&y<=m&I.Contains(y)?
                    j<0?2:3: // _ or - if required
                4]; // otherwise a space

            System.Console.WriteLine(r); // print current line
        }
    }
}
VisualMelon
la source
0

APL (Dyalog Classic) , 151 octets (93 avec l'encodage APL classique)

{a0⍴⍨1 0+1 2×n←⌈/⍵⋄a[⊃,/i,¨¨⍵+⍵-1+i←⍳¨⍵]←1⋄a←(⊖⍪-)a⋄a[⊃,/(n+⍵,-⍵),¨¨,⍨i]←2⋄' /_\'[4|(⌽,-)a]}

Essayez-le en ligne!

ngn
la source