Area di un poligono ASCII


31

Dovresti scrivere un programma o una funzione che riceve una stringa che rappresenta un poligono di arte asciutta come input e output ot restituisce l'area del poligono.

L'input è una stringa composta dai caratteri _ / \ L V spacee che newlinedefinisce un semplice poligono (il che significa nessun segmento in più, nessun auto-tocco e nessun autointersezione).

L'area di una singola cella di caratteri è 2

  • _divide la cella in dimensioni 0e2
  • \divide la cella in dimensioni 1e1
  • /divide la cella in dimensioni 1e1
  • Ldivide la cella in dimensioni 0e2
  • Vsuddivide la cella in dimensioni 1e 1(I due lati della Vsaranno sempre sullo stesso lato del poligono in modo che vengano trattati insieme nell'elenco).

Ogni personaggio collega i due angoli della sua cella di carattere che ti aspetti (ad esempio in alto a sinistra e in alto a destra in caso di V).

Un esempio con area 7 ( 1+2+1nella seconda riga e 1+1+1nella terza):

 _
/ \
V\/

Ingresso

  • L'input formerà un rettangolo, ovvero ci sarà lo stesso numero di caratteri tra le nuove righe.
  • Ci possono essere spazi bianchi extra su qualsiasi lato del poligono.
  • Il trascinamento di newline è facoltativo.

Produzione

  • Un singolo numero intero positivo, l'area del poligono.

Esempi

Gli output sono dopo l'ultima riga dei loro input.

  _  
  V  

1

/L
\/

3



    /VV\
    L  /
     L/
14

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

32  

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

45

Questo è code-golf, quindi vince l'ingresso più breve.


il tuo terzo esempio dovrebbe essere 14
Optimizer

@Optimizer Grazie, corretto.
randomra,

La mancanza di ^ intenzionalmente?
RobAu,

@RobAu Sì, non sembra abbastanza buono.
randomra,

Risposte:


5

CJam, 48 43 29 byte

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

Aggiornamento : ho giocato molto a golf usando la matematica e il trucco dello stato * 2 dalla risposta di orlp.

Come funziona (obsoleto, aggiornamento presto)

Dividiamo l'input su newline e quindi per ogni parte manteniamo un contatore di occorrenze di caratteri al contorno L\/. Questo contatore% 2 ci dirà quale delle due partizioni è la quantità da scegliere per tutti i personaggi. Quindi troviamo l'indice di ogni carattere nella stringa L _. \/Vdarà -1riferimento all'ultimo elemento in un array. Dopo aver ottenuto l'indice, usiamo 4558Zb2/per creare l'array [[2 0] [0 2] [0 2] [1 1]]e quindi scegliamo il corretto conteggio usando il contatore.

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

Provalo online qui


22

Pyth, 47 46 45 36 30

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

Spiegazione:

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.

Abbiamo due stati, "nel poligono" e "fuori dal poligono". I seguenti caratteri ciascuno eseguono le seguenti operazioni quando li legge dall'alto in alto a sinistra in basso a destra:

/ \     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

Si noti che "aggiungi uno all'area" e "se in poligono, aggiungi due all'area" si escludono a vicenda.


Sono davvero confuso su come x=funziona. Questo è documentato da qualche parte?
Jakube,

@Jakube È un compito aumentato.
orlp,

@Jakube è come +=o *=o qualsiasi altra cosa. In questo caso xviene usato come xor, quindi è esattamente lo stesso di Python ^=.
isaacg

14

Retina , 293 + 15 = 308 314 385 byte

;`\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>

Ogni riga va in un file separato, quindi ho aggiunto 13 al conteggio dei byte. In alternativa, puoi mettere tutto in un unico file così com'è e usare il -sflag. Il <empty>supporto per file o righe effettivamente vuoti.

Sfortunatamente, ho bisogno di 187 byte solo per convertire il risultato da unario a decimale. Immagino che dovrei davvero implementarlo presto .

Spiegazione

Retina è un linguaggio basato su regex (che ho scritto esattamente per essere in grado di fare cose come questa con regex). Ogni coppia di file / linee definisce una fase di sostituzione, con la prima riga come modello e la seconda riga la stringa di sostituzione. I pattern possono essere preceduti da una `stringa di configurazione delimitata, che può contenere i soliti modificatori regex, nonché alcune opzioni specifiche di Retina. Per il programma di cui sopra, sono le opzioni pertinenti ;, che sopprime l'output di quello stadio e +, che applica la sostituzione in un ciclo fino a quando il risultato non smette di cambiare.

L'idea della soluzione è di contare ogni riga separatamente, perché possiamo sempre decidere dai personaggi già incontrati se siamo all'interno o all'esterno del poligono. Questo significa anche che posso unire l'intera cosa in un'unica riga, perché l'inizio e la fine di una riga sono sempre al di fuori del poligono. Possiamo anche notare che _e lo spazio è completamente identico per un algoritmo di sweep di linea, così come \e /. Quindi, come primo passo ho sostituire tutte le nuove righe e gli spazi per _e tutto \per /semplificare un certo codice in seguito.

Sto tenendo traccia dell'attuale stato interno / esterno con i personaggi ie o, usando anche la is per calcolare l'area. Per fare ciò, comincio anteponendo una oalla linea unita per contrassegnare che siamo fuori dal poligono. Sto anche aggiungendo un iioalla fine dell'input, che userò come ricerca per generare nuovi personaggi.

Quindi, il primo sostituto di grandi dimensioni sostituisce semplicemente uno io oseguito da uno dei /V_Lcon il successivo set di caratteri, inondando e calcolando così l'intera cosa. La tabella di sostituzione ha il seguente aspetto, in cui le colonne corrispondono all'ultimo carattere di quella riga e le righe al carattere successivo (dove si Strova lo spazio e <>una stringa vuota). Ho incluso tutti i caratteri dell'input per mostrare le equivalenze di cui ho già fatto uso:

     i     o

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

Nota che il carattere finale indica sempre se dopo il personaggio ci troviamo all'interno o all'esterno del poligono, mentre il numero di is corrisponde all'area che deve essere aggiunta al poligono. A titolo di esempio, ecco i risultati delle prime quattro iterazioni sull'ultimo input di esempio (questo è stato generato da una versione precedente che ha effettivamente inondato ciascuna riga separatamente, ma il principio è sempre lo stesso):

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

Infine, mi sbarazzo di tutte le os e le interruzioni di riga rimuovendo tutto ciò che corrisponde [^i], e il resto è la conversione da decimale a unaria che è piuttosto noiosa.


4

Perl, 65 58 byte

map{map{$b^=2*y,/\\L,,;$a+=y,/\\V,,||$b}split//}<>;print$a
  • Commuta $ b tra 0 e 2 dopo aver visto / \ o L.
  • Aggiungi 1 a $ a dopo aver visto / \ o V.
  • Aggiungi $ b a $ a dopo aver visto qualcos'altro.

Bella soluzione, Perl è sorprendentemente compatto.
orlp,

1
L'elaborazione dell'input può essere semplificata per ulteriori guadagni:$/=\1;$-^=2*y,/\\L,,,$a+=y,/\\V,,||$-for<>;print$a
nutki

4

GNU sed, 290 + 1

Il + 1 deve tenere conto del -rpassaggio passato a sed. Commenti e spazi bianchi aggiuntivi non conteggiati nel punteggio.

Non ho guardato nei minimi dettagli, ma penso che questo sia probabilmente simile alla risposta Retina di Martin :

:                      # 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

Panoramica

  • Sostituisci ciascuna unità dell'area con due punti :
  • Conta il numero di due punti

Gli appunti

  • sedè orientato alle linee, quindi ha bisogno di un po 'di lavoro per elaborare più linee contemporaneamente. Il Ncomando esegue ciò aggiungendo una nuova riga quindi la riga successiva allo spazio del motivo corrente. La difficoltà Nè che una volta che arriva al flusso di input EOF, si chiude sedcompletamente senza alcuna opzione per eseguire ulteriori elaborazioni. Per ovviare a questo, contiamo il set corrente di due punti alla fine di ogni riga, appena prima di leggere nella riga successiva.

Produzione:

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

3

C, 93 96 108 byte

Modifica: ha preso in considerazione i suggerimenti dell'account nei commenti, ha convertito il tempo in una singola istruzione per il ciclo e ha rimosso completamente la variabile "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);}

Post originale:

Sembrava un problema abbastanza semplice e divertente da farmi finalmente creare un account qui.

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

Il testo poligonale dovrebbe essere passato come primo argomento della riga di comando; questo dovrebbe funzionare con o senza qualsiasi quantità di newline / spazi bianchi.

Questo legge nel poligono solo un carattere alla volta, s cambia se attualmente all'interno o all'esterno del poligono su '/', 'L' o '\' e t aumenta di 1 su '/', 'V', e '\', o di 2 se dentro / 0 se fuori su 'L', '_', spazio e newline.

Questa è la prima volta che provo la mia mano a qualsiasi tipo di "golf" (o C, nella misura in cui differisce dal C ++), quindi ogni critica è apprezzata!


Benvenuto e buon lavoro! Potresti essere in grado di saltare comunque i=t=s=0;penso che C inizializzi tutte le ints su 0. Inoltre, vedi se riesci a trasformare il whileloop in un forloop; che spesso salva pochi byte.
Ypnypn,

Usando l'idea del ciclo for sopra, penso che tu possa fare qualcosa del genere: ...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;...che dovrebbe salvare 4 byte; uno {, uno} e due;
DedaloAlpha,

Inoltre, come accennato in precedenza, le variabili apparentemente globali vengono automaticamente impostate su 0, quindi se int i,t,v;dovesse essere messo in primo piano mainanziché all'interno, potremmo sbarazzarci del i=t=s=0salvataggio totale di altri 7 byte.
DedaloAlpha,

3

POSIX sed, 245 244

POSIX sed, nessuna estensione o regexps esteso. L'input è limitato alla dimensione massima dello spazio di attesa di sed - mandati POSIX almeno 8192; GNU gestisce di più. Questa versione presuppone che non ci siano righe vuote prima o dopo la forma; ulteriori 10 byte di codice, indicati nell'espansione, possono soddisfare questo se è un requisito (la domanda originale non specifica).

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
}

Espanso e annotato

#!/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 byte

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

Cambiamo parte ogni volta che vediamo \, /oppure L; ne aggiungiamo sempre uno per \\, /o V, ma aggiungiamo 2 (se all'interno) o 0 (se all'esterno) per spazio, newline Lo _.

Le variabili ae isono considerati pari a zero in entrata - devono essere ripristinato quando la funzione è quella di essere chiamato più di una volta.

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

Programma di 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;
}
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.