Aire d'un polygone ASCII


31

Vous devez écrire un programme ou une fonction qui reçoit une chaîne représentant un polygone ascii-art en entrée et en sortie ot renvoie la zone du polygone.

L'entrée est une chaîne composée des caractères _ / \ L V spaceet newlinedéfinissant un polygone simple (ce qui signifie pas de segments supplémentaires, pas d'auto-toucher et pas d'auto-intersection).

L'aire d'une cellule à caractère unique est 2

  • _divise la cellule en tailles 0et2
  • \divise la cellule en tailles 1et1
  • /divise la cellule en tailles 1et1
  • Ldivise la cellule en tailles 0et2
  • Vdivise la cellule en tailles 1et 1(les deux côtés de la Vseront toujours du même côté du polygone afin qu'ils soient traités ensemble dans la liste.)

Chaque personnage relie les deux coins de sa cellule de personnage que vous attendez (par exemple en haut à gauche et en haut à droite en cas de V).

Un exemple avec une zone de 7 ( 1+2+1dans la deuxième rangée et 1+1+1dans la troisième):

 _
/ \
V\/

Contribution

  • L'entrée formera un rectangle, c'est-à-dire qu'il y aura le même nombre de caractères entre les retours à la ligne.
  • Il peut y avoir des espaces supplémentaires sur n'importe quel côté du polygone.
  • Le retour à la ligne est facultatif.

Sortie

  • Un seul entier positif, l'aire du polygone.

Exemples

Les sorties se trouvent après la dernière ligne de leurs entrées.

  _  
  V  

1

/L
\/

3



    /VV\
    L  /
     L/
14

  ____/\ 
  \    /
/\/   /
\____/

32  

   /V\
  /   \__ 
  \     /
/\/   /V
L____/

45

Il s'agit de code-golf, donc l'entrée la plus courte l'emporte.


votre troisième exemple devrait être 14
Optimizer

@Optimizer Merci, corrigé.
randomra

Est-ce le manque de ^ intentionnellement?
RobAu

@RobAu Oui, cela ne semble pas assez bon.
randomra

Réponses:


5

CJam, 48 43 29 octets

qN-{i_9%2%U!^:U;J%D%1U2*?}%:+

Mise à jour : beaucoup joué au golf en utilisant les mathématiques et l'astuce state * 2 de la réponse de orlp.

Comment cela fonctionne (obsolète, mise à jour bientôt)

Nous avons divisé l'entrée sur les nouvelles lignes et puis pour chaque partie , nous maintenons un compteur d'occurrences de caractères limites L\/. Ce compteur% 2 nous indiquera laquelle des deux partitions revient à choisir pour tous les caractères. Ensuite, nous trouvons l'index de chaque caractère dans la chaîne L _. \/Vdonnera -1référence au dernier élément d'un tableau. Après avoir obtenu l'index, nous utilisons 4558Zb2/pour créer le tableau [[2 0] [0 2] [0 2] [1 1]], puis choisissons le bon nombre en utilisant le compteur.

qN/0f{                                  }      e# Split the input on newline and for each
      \{                             }/        e# swap the 0 to back and for each char in
                                               e# the line, run this loop
        _"L _"#                                e# Copy the char and get index of it in
                                               e# this string "L _"
               4558Zb                          e# This is basically 4558 3base
                                               e# which comes to be [2 0 0 2 0 2 1 1]
                     2/=                       e# Group into pairs of 2 and choose the
                                               e# correct one.
                        2$=                    e# Based on the counter, choose the correct
                                               e# partition amount
                           @@"\/L"&,+          e# Increment the counter if the char is one
                                               e# of \, / and L
                                       ;       e# Pop the counter after each line loop
                                         :+    e# Sum all the numbers to get area

Essayez-le en ligne ici


22

Pyth, 47 46 45 36 30

FNs.zx=Z}N"\/L"aY|}N"\/V"yZ;sY

Explication:

FNs.z            For every character in input, except newlines...
  x=Z}N"\/L"     Swap state if /, \, or L.
  aY|}N"\/V"yZ;  Append 1 if /, \, or V, else 2 times the state to Y.
sY               Sum Y and print.

Nous avons deux états, "dans le polygone" et "hors du polygone". Les caractères suivants effectuent chacun les opérations suivantes lors de leur lecture de haut en bas à bas à droite:

/ \     swap state, add one to area
V                   add one to area
_ space             if in polygon, add two to area
L       swap state, if in polygon, add two to area

Notez que «ajouter un à la zone» et «si dans un polygone, ajouter deux à la zone» s'excluent mutuellement.


Je suis vraiment confus sur le x=fonctionnement. Est-ce documenté quelque part?
Jakube

@Jakube C'est une mission augmentée.
orlp

@Jakube C'est comme +=ou *=ou quoi que ce soit. Dans ce cas, xest utilisé comme xor, c'est donc exactement la même chose que Python ^=.
isaacg

14

Rétine , 293 + 15 = 308 314 385 octets

;`\s
_
;`\\
/
;`.+
o$0iio
;+`(o(?=/.*(i)|L.*(ii)|V.*(io)|_)|i(?=/.*(io)|L.*(o)|_.*(ii)|V.*(i))).
$1$2$3$4$5$6$7$8
;`o
<empty>
;`ii$
#:0123456789
;+`^(?=i)(i*)\1{9}(?=#.*(0)|i#.*(1)|ii#.*(2)|iii#.*(3)|iiii#.*(4)|iiiii#.*(5)|iiiiii#.*(6)|iiiiiii#.*(7)|iiiiiiii#.*(8)|iiiiiiiii#.*(9))
$1#$2$3$4$5$6$7$8$9$10$11
:.*|\D
<empty>

Chaque ligne va dans un fichier séparé, j'ai donc ajouté 13 au nombre d'octets. Alternativement, vous pouvez mettre tout cela dans un seul fichier et utiliser l' -sindicateur. Le <empty>support pour les fichiers ou lignes réellement vides.

Malheureusement, j'ai besoin de 187 octets juste pour convertir le résultat de unaire en décimal. Je suppose que je devrais vraiment l' implémenter très bientôt .

Explication

Retina est un langage basé sur l'expression régulière (que j'ai écrit exactement pour pouvoir faire des choses comme ça avec l'expression régulière). Chaque paire de fichiers / lignes définit une étape de remplacement, la première ligne étant le modèle et la deuxième ligne la chaîne de remplacement. Les modèles peuvent être précédés d'une `chaîne de configuration délimitée, qui peut contenir les modificateurs d'expression régulière habituels, ainsi que certaines options spécifiques à Retina. Pour le programme ci-dessus, les options pertinentes sont ;, ce qui supprime la sortie de cette étape et +, qui applique le remplacement dans une boucle jusqu'à ce que le résultat cesse de changer.

L'idée de la solution est de compter chaque ligne séparément, car nous pouvons toujours décider par les caractères déjà rencontrés si nous sommes à l'intérieur ou à l'extérieur du polygone. Cela signifie également que je peux joindre le tout en une seule ligne, car le début et la fin d'une ligne sont toujours en dehors du polygone. Nous pouvons également noter que _et l'espace sont complètement identiques pour un algorithme de balayage de ligne, ainsi que \et /. Donc , dans un premier temps je remplace tous les espaces et les sauts de ligne par _et tout \en /simplifier un code plus tard.

Je garde une trace de l'état intérieur / extérieur actuel avec les personnages iet o, tout en utilisant le is pour cadrer la zone. Pour ce faire, je commence par ajouter un oà la ligne jointe pour marquer que nous sommes en dehors du polygone. J'ajoute également un iioà la toute fin de l'entrée, que j'utiliserai comme recherche pour générer de nouveaux caractères.

Ensuite, le premier grand remplacement remplace simplement un iou osuivi par un /V_Lavec le jeu de caractères suivant, inondant et comptant ainsi le tout. La table de remplacement se présente comme suit, où les colonnes correspondent au dernier caractère de cette ligne et les lignes au caractère suivant (où Sest pour l'espace et <>pour une chaîne vide). J'ai inclus tous les caractères de l'entrée pour montrer les équivalences que j'ai déjà utilisées:

     i     o

/    io    i
\    io    i
L    o     ii
V    i     io
_    ii    <>
S    ii    <>

Notez que le caractère final indique alors toujours si après le caractère nous sommes à l'intérieur ou à l'extérieur du polygone, tandis que le nombre de is correspond à la zone qui doit être ajoutée au polygone. À titre d'exemple, voici les résultats des quatre premières itérations sur le dernier exemple d'entrée (cela a été généré par une ancienne version qui inondait réellement chaque ligne séparément, mais le principe est toujours le même):

o   /V\
o  /   \___
o  L     _/
o/\/   /V
oL__ _/
o   V

o  /V\
o /   \___
o L     _/
oi\/   /V
oii__ _/
o  V

o /V\
o/   \___
oL     _/
oiio/   /V
oiiii_ _/
o V

o/V\
oi   \___
oii     _/
oiioi   /V
oiiiiii _/
oV

oiV\
oiii  \___
oiiii    _/
oiioiii  /V
oiiiiiiii_/
oio

Enfin, je me débarrasse de tous les os et des sauts de ligne en supprimant tout ce qui correspond [^i], et le reste est la conversion décimale-unaire qui est plutôt ennuyeuse.


4

Perl, 65 58 octets

map{map{$b^=2*y,/\\L,,;$a+=y,/\\V,,||$b}split//}<>;print$a
  • Basculez $ b entre 0 et 2 en voyant / \ ou L.
  • Ajoutez 1 à $ a en voyant / \ ou V.
  • Ajoutez $ b à $ a en voyant autre chose.

Belle solution, Perl est étonnamment compact.
orlp le

1
Le traitement des entrées peut être simplifié pour encore plus de gains:$/=\1;$-^=2*y,/\\L,,,$a+=y,/\\V,,||$-for<>;print$a
nutki

4

GNU sed, 290 + 1

Le + 1 tient compte du -rpassage passé à sed. Les commentaires et les espaces supplémentaires ne sont pas pris en compte dans la partition.

Je n'ai pas regardé en détail, mais je pense que cela est probablement similaire à la réponse de Martin's Retina :

:                      # label to start processing next (or first) line
s/[0-9]//g             # remove the count of colons from previous lines
H                      # append the current line to the hold space
g                      # copy the hold space to the pattern space
y^_\\^ /^              # Replace '_' with ' ' and replace '\' with '/'
s/(\n| +$)//g          # strip newlines and trailing space
:o                     # start of "outside loop"
s/(^|:) *V/\1:/        # replace leading spaces and "V" with ":"
to                     #   if the above matches, stay outside
s/(^|:) *[|/]/\1:/     # replace leading spaces and "|" or "/" with ":"
ti                     #   if the above matches, go inside
s/(^|:) *L/\1::/       # replace leading spaces and "L" with "::"
:i                     # start of "inside" loop
s/: /:::/              # replace space with "::"
ti                     #   if the above matches, stay inside
s/:V/::/               # replace "V" with ":"
ti                     #   if the above matches, stay inside
s/:[|/]/::/            # replace "|" or "/" with ":"
to                     #    if the above matches, go outside
s/:L/:/                # remove "L"
to                     #    if the above matches, go outside
h                      # copy current string of colons to hold buffer
:b                     # start of colon count loop
s/:{10}/</g            # standard sed "arithmetic" to get string length
s/<([0-9]*)$/<0\1/
s/:{9}/9/
s/:{8}/8/
s/:{7}/7/
s/:{6}/6/
s/:{5}/5/
s/::::/4/
s/:::/3/
s/::/2/
s/:/1/
s/</:/g
tb                     # once arithmetic done, pattern buffer contains string length
N                      # append newline and next line to pattern buffer
b                      # loop back to process next line

Vue d'ensemble

  • Remplacez chaque unité de surface par deux points :
  • Comptez le nombre de deux points

Remarques

  • sedest orienté ligne et nécessite donc un certain travail pour traiter plusieurs lignes à la fois. La Ncommande fait cela en ajoutant une nouvelle ligne puis la ligne suivante à l'espace de motif actuel. Le problème Nest qu'une fois arrivé au flux d'entrée EOF, il se ferme sedcomplètement sans aucune option pour poursuivre le traitement. Pour contourner ce problème, nous comptons l'ensemble actuel de deux points à la fin de chaque ligne, juste avant de lire la ligne suivante.

Sortie:

$ echo '   /V\
  /   \__ 
  \     /
/\/   /V
L____/' |sed -rf polyarea.sed
45
$

3

C, 93 96 108 octets

Edit: pris en compte les suggestions dans les commentaires, converti le while en une seule instruction for loop et supprimé complètement la variable "i".

int s,t;main(c,v)char**v;{for(;c=*v[1]++;t+=s+(c>46^!(c%19)^s))s^=c>13^c%9>4;printf("%d",t);}

Message d'origine:

Cela ressemblait à un problème amusant et assez simple pour enfin me faire créer un compte ici.

main(c,v)char**v;{int i,t,s;i=t=s=0;while(c=v[1][i++]){s^=c>13^c%9>4;t+=s+(c>46^!(c%19)^s);}printf("%d",t);}

Le texte du polygone doit être transmis comme premier argument de ligne de commande; cela devrait fonctionner avec ou sans aucune quantité de nouvelles lignes / espaces.

Cela lit juste dans le polygone un caractère à la fois, s bascule actuellement dans ou en dehors du polygone sur '/', 'L' ou '\', et t augmente de 1 sur '/', 'V', et '\', ou par 2 si à l'intérieur / 0 si à l'extérieur sur 'L', '_', espace et nouvelle ligne.

C'est la première fois que je m'essaie à n'importe quelle sorte de "golf" (ou C, dans la mesure où il diffère du C ++), donc toutes les critiques sont appréciées!


Bienvenue et bon travail! Vous pourrez peut-être sauter le i=t=s=0;je pense que C initialise tous les ints à 0 de toute façon. Vérifiez également si vous pouvez transformer la whileboucle en forboucle; qui économise souvent quelques octets.
Ypnypn

En utilisant l'idée de la boucle for ci-dessus, je pense que vous pouvez faire quelque chose comme ceci: ...int i,t,s;for(i=t=s=0;c=v[1][i++];t+=s+(c>46^!(c%19)^s))s^=c>13^c%9>4;...qui devrait économiser 4 octets; un {, un} et deux;
DaedalusAlpha

De plus, comme mentionné ci-dessus, les variables apparemment globales sont automatiquement définies sur 0, donc si nous devions les int i,t,v;mettre devant et mainnon à l'intérieur, nous pourrions nous débarrasser de i=t=s=07 autres octets.
DaedalusAlpha

3

POSIX sed, 245 244

POSIX sed, aucune extension ou regexps étendue. L'entrée est limitée à la taille maximale de l'espace de maintien des mandats sed - POSIX au moins 8192; GNU gère plus. Cette version suppose qu'il n'y aura pas de lignes vides avant ou après la forme; 10 octets de code supplémentaires, indiqués dans l'extension, peuvent y répondre si c'est une exigence (la question d'origine ne le précise pas).

H
/^\([L\\]_*\/\|V\| \)*$/!d
x
s/[_ ]/  /g
s/^/!/
s/$/!/
:g
s/\([^V]\)V/V\1/
tg
y/V/ /
s/L/!  /g
s,[/\\], ! ,g
s/![^!]*!//g
:d
/ /{
s/     /v/g
s/vv/x/g
/[ v]/!s/\b/0/2
s/  /b/g
s/bb/4/
s/b /3/
s/v /6/
s/vb/7/
s/v3/8/
s/v4/9/
y/ bvx/125 /
td
}

Développé et annoté

#!/bin/sed -f

# If leading blank lines may exist, then delete them
# (and add 8 bytes to score)
#/^ *$/d

# Collect input into hold space until we reach the end of the figure
# The end is where all pieces look like \___/ or V
H
/^\([L\\]_*\/\|V\| \)*$/!d

x

# Space and underscore each count as two units
s/[_ ]/  /g

# Add an edge at the beginning and end, so we can delete matching pairs
s/^/!/
s/$/!/
# Move all the V's to the beginning and convert each
# to a single unit of area
:gather
s/\([^V]\)V/V\1/
tgather
y/V/ /

# L is a boundary to left of cell; / and \ in middle
s/L/!  /g
s,[/\\], ! ,g

# Strip out all the bits of outer region
s/![^!]*!//g

# Now, we have a space for each unit of area, and no other characters
# remaining (spaces are convenient because we will use \b to match
# where they end).  To count the spaces, we use roman numerals v and x
# to match five and ten, respectively.  We also match two (and call
# that 'b').  At the end of the loop, tens are turned back into spaces
# again.
:digit
/ /{
s/     /v/g
s/vv/x/g
/[ v]/!s/\b/0/2
s/  /b/g
s/bb/4/
s/b /3/
s/v /6/
s/vb/7/
s/v3/8/
s/v4/9/
y/ bvx/125 /
tdigit
}

# If trailing blank lines may exist, then stop now
# (and add 2 bytes to score)
#q

1

C, 84 octets

a;i;f(char*s){for(;*s;a+=strchr("\\/V",*s++)?1:i+i)i^=!strchr("\nV_ ",*s);return a;}

Nous changeons de côté chaque fois que nous voyons \, /ou L; nous en ajoutons toujours un pour \\, /ou V, mais ajoutons 2 (si à l'intérieur) ou 0 (si à l'extérieur) pour l'espace, la nouvelle ligne Lou _.

Les variables aet isont supposées être nulles à l'entrée - elles doivent être réinitialisées si la fonction doit être appelée plus d'une fois.

Ungolfed:

int a;                          /* total area */
int i;                          /* which side; 0=outside */
int f(char*s)
{
    while (*s) {
        i ^= !strchr("\nV_ ",*s);
        a += strchr("\\/V",*s++) ? 1 : i+i;
    }
    return a;
}

Programme de test:

#include <stdio.h>
int main()
{
    char* s;
    s = "  _  \n"
        "  V  \n";
    printf("%s\n%d\n", s, f(s));
    a=i=0;

    s = "/L\n"
        "\\/\n";
    printf("%s\n%d\n", s, f(s));
    a=i=0;


    s = "    /VV\\\n"
        "    L  /\n"
        "     L/";
    printf("%s\n%d\n", s, f(s));
    a=i=0;

    s = "  ____/\\ \n"
        "  \\    /\n"
        "/\\/   /\n"
        "\\____/";
    printf("%s\n%d\n", s, f(s));
    a=i=0;

    s = "   /V\\\n"
        "  /   \\__ \n"
        "  \\     /\n"
        "/\\/   /V\n"
        "L____/";
    printf("%s\n%d\n", s, f(s));
    a=i=0;

    return 0;
}
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.