ASCII poligonunun alanı


31

Giriş ve çıkış çokgen alanını döndürürken, bir sanat eseri poligonunu temsil eden bir dize alan bir program veya işlev yazmalısınız.

Giriş, karakterlerden oluşan _ / \ L V spaceve basit bir çokgeninnewline tanımlandığı bir dizedir (bu, fazladan bölüm yok, kendi kendine dokunma ve kendi kendine kesişme olmaması anlamına gelir).

Tek karakterli bir hücrenin alanı 2

  • _hücreyi boyutlara böler 0ve2
  • \hücreyi boyutlara böler 1ve1
  • /hücreyi boyutlara böler 1ve1
  • Lhücreyi boyutlara böler 0ve2
  • Vhücreyi boyutlara böler 1ve 1(İsteğin iki tarafı Vher zaman çokgenin aynı tarafında olur, böylece listede birlikte işlem görürler.)

Her karakter, beklediğiniz karakter hücresinin iki köşesini birleştirir (örn. Durumunda üst sol ve üst sağ V).

7 alanlı bir örnek ( 1+2+1ikinci sırada ve 1+1+1üçüncü sırada):

 _
/ \
V\/

Giriş

  • Giriş bir dikdörtgen oluşturacak, yani yeni satırlar arasında aynı sayıda karakter bulunacaktır.
  • Poligonun herhangi bir tarafında ekstra boşluk olabilir.
  • İzleyen yeni satır isteğe bağlıdır.

Çıktı

  • Tek bir pozitif tamsayı, çokgen alanı.

Örnekler

Çıkışlar girişlerinin son satırından sonradır.

  _  
  V  

1

/L
\/

3



    /VV\
    L  /
     L/
14

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

32  

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

45

Bu kod golf yani en kısa giriş kazanır.


üçüncü örneğiniz 14 olmalıdır
Optimize Edici,

@Optimizer Teşekkürler, düzeltildi.
randomra

Eksikliği mi ^ kasıtlı?
RobAu,

@RobAu Evet, bu yeterince iyi görünmüyor.
randomra

Yanıtlar:


5

CJam, 48 43 29 bayt

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

Güncelleme : Matematik ve devlet kullanarak çok golf oynadım * 2 orlp cevabından hüner.

Nasıl çalışır (Eski, yakında güncelleniyor)

Girdiyi yeni satırda bölüyoruz ve sonra her bölüm için bir sınır karakterleri oluşumu karşıtı tutuyoruz L\/. Bu% 2 sayacı bize iki bölümden hangisinin tüm karakterler için seçileceğini söyleyecektir. Sonra dizedeki her karakterin dizinini buluruz L _. bir dizideki son öğeye atıfta \/Vbulunacaktır -1. Dizini aldıktan sonra 4558Zb2/, diziyi oluşturmak için kullanırız [[2 0] [0 2] [0 2] [1 1]]ve sonra sayacı kullanarak sayımın doğruluğunu seçeriz.

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

Burada çevrimiçi deneyin


22

Pyth, 47 46 45 36 30

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

Açıklama:

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.

"Çokgenin içinde" ve "çokgenin dışında" olmak üzere iki durum var. Aşağıdaki karakterlerin her biri üst soldan alt sağa okurken aşağıdakileri yapar:

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

"Alana bir tane ekle" ve "Çokgen ise, bölgeye iki tane ekle" özel amaçlıdır.


Gerçekten nasıl x=çalıştığı konusunda kafam karıştı . Bu bir yerde belgeleniyor mu?
Jakube

@Jakube Artırılmış atama.
orlp

@Jakube Bu, +=ya *=da her neyse. Bu durumda xxor olarak kullanılıyor, bu yüzden Python's ile tamamen aynı ^=.
isaacg

14

Retina , 293 + 15 = 308 314 385 bayt

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

Her satır ayrı bir dosyaya gider, bu yüzden bayt sayısına 13 ekledim. Alternatif olarak, hepsini olduğu gibi tek bir dosyaya koyabilir ve -sbayrağı kullanabilirsiniz . <empty>Aslında boş dosyaları veya hatlar için standı.

Maalesef, sonucu unary'den ondalık basamağa dönüştürmek için 187 bayta ihtiyacım var. Sanırım bunu bir süre sonra uygulamaya geçirmeliyim .

açıklama

Retina, regex tabanlı bir dildir (tam olarak regex ile böyle şeyler yapabilmek için yazdığım). Her dosya / çizgi çifti, bir değiştirme aşamasını tanımlar; ilk satır, desen ve ikinci satır, değiştirme dizesidir. Desenler `, normal regex değiştiricilerin yanı sıra bazı Retinaya özgü seçenekler içerebilen sınırlandırılmış bir yapılandırma dizesi ile gelebilir. Yukarıdaki program için, ;o aşamadaki çıktısını bastıran +ve sonuç değişmeyi durdurana kadar değiştirme işlemini bir döngü halinde uygulayan ilgili seçenekler vardır .

Çözümün fikri, her bir çizgiyi ayrı ayrı saymaktır, çünkü çokgen içinde veya dışında olup olmadığımızla her zaman karşılaştığımız karakterlere karar verebiliriz. Bu aynı zamanda her şeyi tek bir çizgide birleştirebileceğim anlamına geliyor, çünkü çizginin başına ve sonuna gitmek her zaman çokgenin dışındadır. Ayrıca not edebilirsiniz _ve uzay bir çizgi süpürme algoritması için tamamen aynıdır, hem de \ve /. Tarafından Yani ilk adım olarak tüm yeni satır ve boşlukların yerine _ve tüm \tarafından /daha sonra bazı kodlar basitleştirmek için.

Şu andaki iç / dış durumu karakterlerle takip ediyorum ive oaynı zamanda ibölgeyi taklit etmek için s'yi kullanıyorum . Bunun oiçin poligonun dışında olduğumuzu işaretlemek için bir birleştirilmiş çizgiye hazırlanarak başlıyorum. Ayrıca iioyeni karakterler oluşturmak için bir arama olarak kullanacağım girişin sonuna bir ekleme yapıyorum.

Ardından, ilk büyük değişim bir iveya daha osonra bir /V_Lsonraki karakter grubundan birinin yerine geçer , böylece her şeyi siler ve konuşur. Değiştirme tablosu, sütunların bu satırdaki son karaktere karşılık geldiği ve satırların bir sonraki karaktere karşılık geldiği ( Sboşluk ve <>boş bir dize için) olduğu gibi görünür . Kullandığım eşdeğerleri göstermek için girişin tüm karakterlerini dahil ettim:

     i     o

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

Not nihai karakter sonra hep gösterir olsun sonra karakterin Bizler içinde veya çokgen dışında iken sayısı iihtiyaçları poligon eklenecek o bölgeye ler tekabül. Bir örnek olarak, son örnek girişindeki ilk dört yinelemenin sonuçları (bu, her bir satırı ayrı ayrı su basan eski bir sürüm tarafından oluşturuldu, ancak ilke hala aynı):

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

Son olarak, oeşleşen her şeyi kaldırarak tüm s ve satır kesmelerinden kurtuldum [^i]ve geri kalanı, oldukça sıkıcı olan ondalık birime dönüşüm.


4

Perl, 65 58 bayt

map{map{$b^=2*y,/\\L,,;$a+=y,/\\V,,||$b}split//}<>;print$a
  • / \ Veya L'yi görünce $ b ile 0 ile 2 arasında geçiş yapın.
  • / \ Veya V göründüğünde $ 1 a ekleyin.
  • Başka bir şey gördüğünüzde $ b'ye $ b ekleyin.

Güzel çözüm, Perl şaşırtıcı derecede kompakt.
orlp

1
Giriş işleme daha fazla kazanç için basitleştirilebilir:$/=\1;$-^=2*y,/\\L,,,$a+=y,/\\V,,||$-for<>;print$a
nutki

4

GNU sed, 290 + 1

+ 1, -rsed'e geçirilen anahtarı hesaba katar . Yorumlar ve ek boşluklar skorda sayılmaz.

Daha ayrıntılı bakmadım, ancak sanırım bu muhtemelen Martin Retina'nın cevabına benziyor :

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

genel bakış

  • Her alan birimini iki nokta üst üste ile değiştirin :
  • Sütun sayısını say

notlar

  • sedSatır yönelimli olduğundan, aynı anda birden fazla satırın işlenmesi için bazı çalışmalara ihtiyaç vardır. NKomut sonra geçerli desen alanı yanındaki satırı bir yeni satır ekleyerek yapar. Zorluk, NEOF giriş akışına bir kez ulaştığında, seddaha fazla işlem yapmak için herhangi bir seçenek olmadan tamamen bırakmasıdır . Bunu aşmak için, bir sonraki satırda okumadan hemen önce, her satırın sonundaki geçerli iki nokta kümesini sayarız.

Çıktı:

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

3

C, 93 96 108 bayt

Düzenleme: Yorumlarda önerileri dikkate aldı, süresi bir tek-ifadeye dönüştürdü ve "i" değişkenini tamamen kaldırdı.

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

Orijinal yayın:

Bu, nihayet burada bir hesap oluşturmamı sağlayacak kadar eğlenceli ve basit bir problem gibi görünüyordu.

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

Çokgen metin ilk komut satırı argümanı olarak iletilmelidir; bu, herhangi bir miktarda yeni satır / boşluk olmadan çalışmalıdır.

Bu sadece bir defada poligonda bir karakter okur, s şu anda poligonun içinde veya dışında '/', 'L' veya '\' de olup olmadığını değiştirir ve t '/', 'V' değerinde 1 artar, ve '\' veya 'L', '_' içindeyse / 0 içindeyseniz / boşluk, newline.

Bu benim ilk kez elimi herhangi bir "golf" (ya da C, C ++ 'dan farklı bir ölçüde) kullanarak denemektir;


Hoşgeldin ve iyi iş! Sen atlamak mümkün olabilir i=t=s=0;C bütün başlatır düşünüyorum int0 oldu Neyse için s. Ayrıca, whiledöngüyü bir fordöngüye dönüştürebiliyor musunuz bakalım ; Bu genellikle birkaç bayt kazandırır.
Ypnypn

Yukarıdaki for döngüsü fikrini kullanarak, bunun gibi bir şey yapabileceğinizi düşünüyorum : ...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;...4 byte tasarruf etmeli; bir {, bir} ve iki;
DaedalusAlpha

Yukarıda da belirtildiği gibi, görünüşe göre global değişkenler otomatik olarak 0'a ayarlanmıştır, bu yüzden eğer içeriye değil de int i,t,v;önüne mainkonulursa, i=t=s=0başka bir 7 byte'lık tasarruftan tamamen kurtulabiliriz .
DaedalusAlpha

3

POSIX sed, 245 244

POSIX sed, uzantı yok veya uzatılmış regexps. Girdi, sed'in maksimum tutma alanı büyüklüğü ile sınırlıdır - POSIX en az 8192; GNU daha fazlasını yönetir. Bu sürüm, şekilden önce veya sonra boş satır olmayacağını varsayar; Genişlemede belirtilen 10 baytlık ekstra bir kod, eğer gerekliyse (asıl soru belirtmiyorsa) buna uygun olabilir.

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
}

Genişletilmiş ve açıklamalı

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

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

Biz gördüklerinde taraf değiştirmeye \, /veya L; biz her zaman için bir ekleme \\, /veya V, fakat 2 ekleyin (iç) veya 0 (eğer dışında) alanı, yeni satır için Lveya _.

Değişkenler ave igirişte sıfır olduğu varsayılır - işlev bir kereden fazla çağrılıyorsa sıfırlanmaları gerekir.

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

Test programı:

#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;
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.