Area poligon ASCII

31

Anda harus menulis program atau fungsi yang menerima string yang mewakili poligon ascii-art sebagai input dan output mengembalikan area poligon.

Input adalah string yang terdiri dari karakter _ / \ L V spacedan newlinemendefinisikan poligon sederhana (yang berarti tidak ada segmen tambahan, tidak ada sentuhan diri, dan tidak ada persimpangan diri).

Luas sel karakter tunggal adalah 2

  • _membelah sel menjadi ukuran 0dan2
  • \membelah sel menjadi ukuran 1dan1
  • /membelah sel menjadi ukuran 1dan1
  • Lmembelah sel menjadi ukuran 0dan2
  • Vmembelah sel menjadi ukuran 1dan 1(Kedua sisi Vakan selalu berada di sisi yang sama dari poligon sehingga mereka diperlakukan bersama dalam daftar.)

Setiap karakter menghubungkan dua sudut sel karakternya yang Anda harapkan (misalnya kiri atas dan kanan atas jika ada V).

Contoh dengan area 7 ( 1+2+1di baris kedua dan 1+1+1yang ketiga):

 _
/ \
V\/

Memasukkan

  • Input akan membentuk persegi panjang, yaitu akan ada jumlah karakter yang sama antara baris baru.
  • Mungkin ada spasi putih tambahan di setiap sisi poligon.
  • Mengejar baris baru adalah opsional.

Keluaran

  • Bilangan bulat positif tunggal, bidang poligon.

Contohnya

Keluaran adalah setelah baris terakhir dari input mereka.

  _  
  V  

1

/L
\/

3



    /VV\
    L  /
     L/
14

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

32  

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

45

Ini adalah kode-golf sehingga entri terpendek menang.

randomra
sumber
contoh ketiga Anda harus 14
Pengoptimal
@Optimizer Terima kasih, diperbaiki.
randomra
Apakah kurangnya ^ sengaja?
RobAu
@RobAu Ya, itu tidak terlihat cukup baik.
randomra

Jawaban:

5

CJam, 48 43 29 byte

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

Pembaruan : Golf banyak menggunakan matematika dan trik * 2 negara dari jawaban orlp.

Cara kerjanya (Sudah kedaluwarsa, segera diperbarui)

Kami membagi input pada baris baru dan kemudian untuk setiap bagian kami mempertahankan counter kemunculan karakter batas L\/. Penghitung ini% 2 akan memberi tahu kami yang mana dari dua partisi yang akan dipilih untuk semua karakter. Kemudian kita menemukan indeks masing-masing karakter dalam string L _. \/Vakan memberikan -1merujuk pada elemen terakhir dalam array. Setelah mendapatkan indeks, kami menggunakan 4558Zb2/untuk membuat array [[2 0] [0 2] [0 2] [1 1]]dan kemudian memilih yang benar dari penghitungan menggunakan penghitung.

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

Cobalah online di sini

Pengoptimal
sumber
22

Pyth, 47 46 45 36 30

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

Penjelasan:

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.

Kami memiliki dua negara, "dalam poligon", dan "keluar dari poligon". Masing-masing karakter berikut melakukan hal berikut saat membacanya dari kiri atas ke kanan bawah:

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

Perhatikan bahwa "tambahkan satu ke area" dan "jika dalam poligon, tambahkan dua ke area" adalah saling eksklusif.

orlp
sumber
Saya benar-benar bingung bagaimana cara x=kerjanya. Apakah ini didokumentasikan di suatu tempat?
Jakube
@ Jakube Ini tugas tambahan.
orlp
@ Jakube Ini seperti +=atau *=atau apa pun. Dalam hal xini digunakan sebagai xor, jadi persis sama dengan 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>

Setiap baris masuk dalam file yang terpisah, jadi saya telah menambahkan 13 ke jumlah byte. Atau, Anda dapat meletakkan semua itu dalam satu file apa adanya dan menggunakan -sbendera. The <empty>berdiri untuk file benar-benar kosong atau baris.

Sayangnya, saya perlu 187 byte hanya untuk mengubah hasil dari unary ke desimal. Saya kira saya benar-benar harus menerapkan ini dalam waktu dekat .

Penjelasan

Retina adalah bahasa berbasis regex (yang saya tulis persis karena bisa melakukan hal-hal seperti ini dengan regex). Setiap pasangan file / baris menentukan tahap penggantian, dengan baris pertama menjadi pola dan baris kedua sebagai string pengganti. Pola dapat didahului oleh `string konfigurasi -dimited, yang mungkin berisi pengubah regex biasa, serta beberapa opsi khusus Retina. Untuk program di atas, opsi yang relevan adalah ;, yang menekan output dari tahap itu dan +, yang menerapkan penggantian dalam satu lingkaran sampai hasilnya berhenti berubah.

Gagasan solusinya adalah menghitung setiap baris secara terpisah, karena kita selalu dapat memutuskan oleh karakter yang sudah kita temui apakah kita di dalam atau di luar poligon. Ini juga berarti saya dapat menggabungkan semuanya menjadi satu baris, karena awal dan akhir baris selalu di luar poligon. Kami juga dapat mencatat bahwa _dan ruang benar-benar identik untuk algoritme garis, serta \dan /. Jadi sebagai langkah pertama saya mengganti semua baris baru dan spasi dengan _dan semua \dengan /menyederhanakan beberapa kode nanti.

Saya melacak keadaan dalam / luar saat ini dengan karakter idan o, sementara juga menggunakan is untuk menghitung daerah. Untuk melakukannya, saya mulai dengan menambahkan sebuah oke baris yang bergabung untuk menandai bahwa kita berada di luar poligon. Saya juga menambahkan iiohingga akhir input, yang akan saya gunakan sebagai pencarian untuk menghasilkan karakter baru.

Kemudian, penggantian besar pertama hanya mengganti iatau odiikuti oleh salah satu dari /V_Lset karakter berikutnya, sehingga membanjiri dan menghitung seluruh hal. Tabel penggantian terlihat sebagai berikut, di mana kolom terkait dengan karakter terakhir di baris itu dan baris ke karakter berikutnya (di mana Sadalah untuk ruang dan <>untuk string kosong). Saya telah memasukkan semua karakter input untuk menunjukkan persamaan yang telah saya manfaatkan:

     i     o

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

Perhatikan bahwa karakter terakhir kemudian selalu menunjukkan apakah setelah karakter kita berada di dalam atau di luar poligon, sementara jumlah is sesuai dengan area yang perlu ditambahkan ke poligon. Sebagai contoh di sini adalah hasil dari empat iterasi pertama pada input contoh terakhir (ini dihasilkan oleh versi lama yang sebenarnya membanjiri setiap baris secara terpisah, tetapi prinsipnya masih 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

Terakhir, saya menyingkirkan semua os dan garis terputus dengan menghapus semua yang cocok [^i], dan sisanya adalah konversi desimal ke unary yang agak membosankan.

Martin Ender
sumber
4

Perl, 65 58 byte

map{map{$b^=2*y,/\\L,,;$a+=y,/\\V,,||$b}split//}<>;print$a
  • Beralih $ b antara 0 dan 2 setelah melihat / \ atau L.
  • Tambahkan 1 hingga $ a setelah melihat / \ atau V.
  • Tambahkan $ b ke $ a setelah melihat yang lain.
Helios
sumber
Solusi yang bagus, Perl sangat kompak.
orlp
1
Pemrosesan input dapat disederhanakan untuk beberapa keuntungan lagi:$/=\1;$-^=2*y,/\\L,,,$a+=y,/\\V,,||$-for<>;print$a
nutki
4

GNU sed, 290 +1

+1 adalah untuk menjelaskan -rsakelar yang diteruskan ke sed. Komentar dan spasi putih tambahan tidak dihitung dalam skor.

Saya belum melihat dengan sangat rinci, tetapi saya pikir ini mungkin mirip dengan jawaban Retina 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

Ikhtisar

  • Ganti setiap unit area dengan tanda titik dua :
  • Hitung jumlah titik dua

Catatan

  • sedberorientasi garis sehingga perlu beberapa pekerjaan untuk memproses beberapa baris sekaligus. The Nperintah ini dilakukan dengan menambahkan baris baru kemudian baris berikutnya ke ruang pola arus. Kesulitan dengan Nadalah bahwa begitu sampai ke aliran input EOF, ia berhenti sedsepenuhnya tanpa opsi untuk melakukan pemrosesan lebih lanjut. Untuk menyiasatinya, kami menghitung kumpulan titik dua saat ini di akhir setiap baris, tepat sebelum membaca di baris berikutnya.

Keluaran:

$ echo '   /V\
  /   \__ 
  \     /
/\/   /V
L____/' |sed -rf polyarea.sed
45
$
Trauma Digital
sumber
3

C, 93 96 108 byte

Sunting: Mengambil saran akun dalam komentar, mengonversikan while menjadi satu pernyataan untuk loop, dan menghapus variabel "i" sepenuhnya.

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

Pos asli:

Ini tampak seperti masalah yang menyenangkan dan cukup sederhana untuk akhirnya membuat saya membuat akun di sini.

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

Teks poligon harus dilewatkan sebagai argumen baris perintah pertama; ini harus bekerja dengan atau tanpa jumlah baris baru / spasi putih.

Ini hanya membaca dalam poligon satu karakter pada satu waktu, beralih apakah saat ini di dalam atau di luar poligon pada '/', 'L', atau '\', dan t bertambah 1 pada '/', 'V', dan '\', atau 2 jika di dalam / 0 jika di luar di 'L', '_', spasi dan baris baru.

Ini adalah pertama kalinya saya mencoba tangan saya dalam segala jenis "golf" (atau C, sejauh itu berbeda dari C ++), jadi kritik apa pun akan dihargai!

Jonathan Aldrich
sumber
Selamat datang dan kerja bagus! Anda mungkin dapat melewatkan i=t=s=0;I think C menginisialisasi semua ints ke 0. Juga, lihat apakah Anda dapat mengubah whileloop menjadi forloop; yang sering menghemat beberapa byte.
Ypnypn
Menggunakan ide for for loop di atas, saya pikir Anda dapat melakukan sesuatu seperti ini: ...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;...yang seharusnya menghemat 4 byte; satu {, satu} dan dua;
DaedalusAlpha
Juga seperti yang disebutkan di atas, tampaknya variabel global secara otomatis diatur ke 0, jadi jika int i,t,v;harus diletakkan di depan mainalih-alih di dalam kita bisa menyingkirkan i=t=s=0sama sekali menghemat 7 byte lainnya.
DaedalusAlpha
3

POSIX, 245 244

POSIX, tidak ada ekstensi atau regexps diperpanjang. Input terbatas pada ukuran ruang penyimpanan maksimum dari mandat - POSIX setidaknya 8192; GNU mengelola lebih banyak. Versi ini mengasumsikan bahwa tidak akan ada garis kosong sebelum atau sesudah bentuk; tambahan 10 byte kode, ditunjukkan dalam ekspansi, dapat mengakomodasi bahwa jika itu merupakan persyaratan (pertanyaan awal tidak menentukan).

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
}

Diperluas dan beranotasi

#!/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
sumber
1

C, 84 byte

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

Kita berpindah sisi kapan pun kita melihat \, /atau L; kami selalu menambahkan satu untuk \\, /atau V, tetapi menambahkan 2 (jika di dalam) atau 0 (jika di luar) untuk ruang, baris baru, Latau _.

Variabel adan idianggap nol pada entri - mereka harus diatur ulang jika fungsinya dipanggil lebih dari sekali.

Tidak Disatukan:

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

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