Obszar wielokąta ASCII

31

Powinieneś napisać program lub funkcję, która jako ciąg wejściowy i wyjściowy zwraca ciąg reprezentujący wielobok ascii-art, a zwraca obszar wielokąta.

Dane wejściowe to ciąg znaków składający się ze znaków _ / \ L V space i newlinedefiniujący prosty wielokąt (co oznacza brak dodatkowych segmentów, brak dotyku i brak przecięcia).

Obszar pojedynczej komórki to 2

  • _ dzieli komórkę na rozmiary 0i2
  • \ dzieli komórkę na rozmiary 1i1
  • / dzieli komórkę na rozmiary 1i1
  • L dzieli komórkę na rozmiary 0i2
  • Vdzieli komórkę na rozmiary 1i1 (Dwie strony Vzawsze będą po tej samej stronie wielokąta, więc są traktowane razem na liście).

Każda postać łączy dwa rogi swojej komórki postaci, której się spodziewasz (np. Lewy górny i prawy górny w przypadku V).

Przykład o powierzchni 7 ( 1+2+1w drugim rzędzie i 1+1+1trzecim):

 _
/ \
V\/

Wkład

  • Dane wejściowe utworzą prostokąt, tzn. Między znakami nowej linii będzie ta sama liczba znaków.
  • Po każdej stronie wielokąta mogą znajdować się dodatkowe białe znaki.
  • Końcowy znak nowej linii jest opcjonalny.

Wydajność

  • Pojedyncza dodatnia liczba całkowita, obszar wielokąta.

Przykłady

Wyjścia są za ostatnim wierszem ich danych wejściowych.

  _  
  V  

1

/L
\/

3



    /VV\
    L  /
     L/
14

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

32  

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

45

To jest golf golfowy, więc wygrywa najkrótszy wpis.

randomra
źródło
twój trzeci przykład to 14
Optymalizator
@Optimizer Dzięki, poprawione.
randomra
Czy brak ^ celowo?
RobAu
@RobAu Tak, to nie wygląda wystarczająco dobrze.
randomra

Odpowiedzi:

5

CJam, 48 43 29 bajtów

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

Aktualizacja : Dużo grałem w golfa przy użyciu matematyki i sztuczki stanowej * 2 z odpowiedzi orlp.

Jak to działa (nieaktualne, wkrótce aktualizacja)

Dzielimy dane wejściowe na nowy wiersz, a następnie dla każdej części utrzymujemy licznik wystąpień znaków granicznych L\/. Ten licznik% 2 powie nam, którą z dwóch partycji wybrać dla wszystkich znaków. Następnie znajdujemy indeks każdego znaku w ciągu L _. \/Vda -1odniesienie do ostatniego elementu w tablicy. Po uzyskaniu indeksu używamy 4558Zb2/do utworzenia tablicy, [[2 0] [0 2] [0 2] [1 1]]a następnie wybieramy poprawną liczbę za pomocą licznika.

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

Wypróbuj online tutaj

Optymalizator
źródło
22

Pyth, 47 46 45 36 30

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

Wyjaśnienie:

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.

Mamy dwa stany: „w wielokącie” i „poza wielokątem”. Następujące znaki wykonują następujące czynności, czytając je od lewego górnego do prawego dolnego rogu:

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

Pamiętaj, że „dodaj jeden do obszaru” i „jeśli w wielokącie, dodaj dwa do obszaru” wykluczają się wzajemnie.

orlp
źródło
Jestem naprawdę zdezorientowany, jak x=działa. Czy to gdzieś jest udokumentowane?
Jakube
@Jakube To rozszerzone zadanie.
orlp
@Jakube To jak +=lub *=czy cokolwiek innego. W tym przypadku xjest używany jako xor, więc jest dokładnie taki sam jak Python ^=.
isaacg
14

Siatkówka oka , 293 + 15 = 308 314 385 bajtów

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

Każda linia przechodzi w osobny plik, więc dodałem 13 do liczby bajtów. Możesz też umieścić to wszystko w jednym pliku i użyć -sflagi. <empty>Oznaczają faktycznie pustych plików lub linii.

Niestety, potrzebuję 187 bajtów, aby przekonwertować wynik z jednostkowego na dziesiętny. Chyba powinienem to niedługo zaimplementować .

Wyjaśnienie

Retina jest językiem opartym na wyrażeniach regularnych (który napisałem właśnie po to, aby móc robić takie rzeczy przy pomocy wyrażeń regularnych). Każda para plików / linii definiuje etap zastępowania, przy czym pierwsza linia to wzorzec, a druga linia ciąg zastępujący. Wzorce mogą być poprzedzone `-delimitowanym ciągiem konfiguracji, który może zawierać zwykłe modyfikatory wyrażeń regularnych, a także niektóre opcje specyficzne dla Retina. Dla powyższego programu odpowiednie opcje to ;, które tłumią wyjście tego etapu i +które stosują zamianę w pętli, aż wynik przestanie się zmieniać.

Ideą rozwiązania jest policzenie każdej linii osobno, ponieważ zawsze możemy zdecydować na podstawie znaków, które już napotkaliśmy, czy jesteśmy wewnątrz wielokąta, czy poza nim. Oznacza to również, że mogę połączyć całość w jedną linię, ponieważ przejście do początku i końca linii zawsze znajduje się poza wielokątem. Możemy również zauważyć, że _i przestrzeń są całkowicie identyczne dla algorytmu przesuwania linii, a także \i/ . Tak jak w pierwszym etapie zastąpić wszystkie znaki nowej linii i przestrzenie autorem _a wszystko \przez/ uproszczenie kodu później.

Śledzę bieżący stan wewnątrz / na zewnątrz z postaciami ii ojednocześnie używam is do zliczania obszaru. Aby to zrobić, zaczynam od dodania odo połączonej linii, aby zaznaczyć, że jesteśmy poza wielokątem. Dodam też iiona samym końcu danych wejściowych, których użyję jako odnośnik do generowania nowych znaków.

Następnie pierwsza duża zamiana po prostu zastępuje jedną ilub onastępną jedną /V_Lz następną serią znaków, zalewając w ten sposób całość. Tabela wymiany wygląda następująco: kolumny odpowiadają ostatniemu znakowi w tej linii, a wiersze do następnego znaku (gdzie Sjest miejsce na spację i <>pusty ciąg znaków). Uwzględniłem wszystkie znaki wejściowe, aby pokazać ekwiwalenty, których już użyłem:

     i     o

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

Zauważ, że końcowy znak zawsze wskazuje, czy po znaku jesteśmy wewnątrz czy poza wielokątem, podczas gdy liczba is odpowiada obszarowi, który należy dodać do wielokąta. Jako przykład podajemy wyniki pierwszych czterech iteracji z ostatniego przykładowego wejścia (zostało to wygenerowane przez starą wersję, która faktycznie zalała każdą linię osobno, ale zasada jest nadal taka sama):

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

Wreszcie, po prostu pozbyłem się wszystkich os i linia łamie się, usuwając wszystko, co pasuje [^i], a reszta to konwersja dziesiętna na unarską, która jest raczej nudna.

Martin Ender
źródło
4

Perl, 65 58 bajtów

map{map{$b^=2*y,/\\L,,;$a+=y,/\\V,,||$b}split//}<>;print$a
  • Przełącz $ b pomiędzy 0 i 2 po zobaczeniu / \ lub L.
  • Dodaj 1 do $ a po obejrzeniu / \ lub V.
  • Dodaj $ b do $ a po zobaczeniu czegokolwiek innego.
Helios
źródło
Ładne rozwiązanie, Perl jest zaskakująco kompaktowy.
lub
1
Przetwarzanie danych wejściowych można uprościć, aby uzyskać więcej korzyści:$/=\1;$-^=2*y,/\\L,,,$a+=y,/\\V,,||$-for<>;print$a
nutki
4

GNU sed, 290 + 1

+ 1 ma uwzględniać -r przełącznika na sed. Komentarze i dodatkowe białe znaki nie są liczone w wyniku.

Nie przyjrzałem się zbyt szczegółowo, ale myślę, że prawdopodobnie jest to podobne do odpowiedzi Retina Martina :

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

Przegląd

  • Zastąp każdą jednostkę obszaru dwukropkiem :
  • Policz liczbę dwukropków

Notatki

  • sedjest zorientowany na linie, więc wymaga trochę pracy, aby przetworzyć wiele linii jednocześnie. NKomenda robi to poprzez dodanie nowego wiersza potem następną linię do aktualnej przestrzeni wzoru. Trudność Npolega na tym, że gdy dotrze do strumienia wejściowego EOF, wychodzi sedcałkowicie bez żadnej opcji dalszego przetwarzania. Aby obejść ten problem, liczymy bieżący zestaw dwukropków na końcu każdej linii, tuż przed czytaniem w następnej linii.

Wydajność:

$ echo '   /V\
  /   \__ 
  \     /
/\/   /V
L____/' |sed -rf polyarea.sed
45
$
Cyfrowa trauma
źródło
3

C, 93 96 108 bajtów

Edycja: wziął pod uwagę sugestie w komentarzach, przekształcił while w pętlę pojedynczą dla pętli i całkowicie usunął zmienną „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);}

Oryginalny post:

Wyglądało to na dość zabawny i prosty problem, że w końcu udało mi się założyć tutaj konto.

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

Tekst wielokąta należy przekazać jako pierwszy argument wiersza poleceń; powinno to działać z dowolną liczbą znaków nowej linii / białych znaków lub bez nich.

To po prostu odczytuje w wielokącie jeden znak na raz, s przełącza, czy obecnie jest w wielokącie, czy poza nim, na „/”, „L” lub „\”, a t wzrasta o 1 na „/”, „V”, i „\” lub o 2, jeśli wewnątrz / 0, jeśli na zewnątrz na „L”, „_”, spacja i nowa linia.

Po raz pierwszy próbuję swoich sił w jakimkolwiek „golfie” (lub C, w stopniu, w jakim różni się od C ++), więc wszelkie uwagi są mile widziane!

Jonathan Aldrich
źródło
Witamy i dobra robota! Możesz być w stanie pominąć i=t=s=0;myślę, że C i tak inicjuje wszystkie ints do 0. Sprawdź także, czy możesz zamienić whilepętlę w forpętlę; co często oszczędza kilka bajtów.
Ypnypn
Korzystając z idei pętli for powyżej, myślę, że możesz zrobić coś takiego: ...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;...co powinno oszczędzić 4 bajty; jeden {, jeden} i dwa;
DaedalusAlpha
Również, jak wspomniano powyżej, pozornie zmienne globalne są automatycznie ustawiane na 0, więc jeśli miałoby int i,t,v;zostać umieszczone przed mainzamiast w środku, moglibyśmy się pozbyć i=t=s=0całkowicie oszczędzając kolejne 7 bajtów.
DaedalusAlpha
3

POSIX sed, 245 244

POSIX sed, bez rozszerzeń i rozszerzonych wyrażeń regularnych. Dane wejściowe są ograniczone do maksymalnego rozmiaru przestrzeni ładunkowej sed - POSIX upoważnia co najmniej 8192; GNU zarządza więcej. Ta wersja zakłada, że ​​przed kształtem lub po nim nie będzie pustych linii; dodatkowe 10 bajtów kodu, wskazanych w rozwinięciu, może to pomieścić, jeśli jest to wymagane (pierwotne pytanie nie określa).

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
}

Rozszerzony i opatrzony adnotacjami

#!/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
Toby Speight
źródło
1

C, 84 bajtów

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

Zmieniamy strony, ilekroć widzimy \, /lub L; zawsze dodajemy jeden dla \\, /lub V, ale dodajemy 2 (jeśli jest w środku) lub 0 (jeśli na zewnątrz) dla spacji, nowej linii,L lub _.

Zmienne a i iprzyjmuje się, że są zerowe przy wprowadzaniu - należy je zresetować, jeśli funkcja ma zostać wywołana więcej niż jeden raz.

Nie golfowany:

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

Program testowy:

#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;
}
Toby Speight
źródło