Diện tích của đa giác ASCII


31

Bạn nên viết một chương trình hoặc hàm nhận chuỗi đại diện cho đa giác ascii-art làm đầu vào và đầu ra ot trả về diện tích của đa giác.

Đầu vào là một chuỗi bao gồm các ký tự _ / \ L V spacenewlinexác định một đa giác đơn giản (có nghĩa là không có phân đoạn phụ, không tự chạm và không tự giao nhau).

Diện tích của một ô ký tự là 2

  • _chia ô thành các kích cỡ 02
  • \chia ô thành các kích cỡ 11
  • /chia ô thành các kích cỡ 11
  • Lchia ô thành các kích cỡ 02
  • Vchia ô thành các kích thước 11(Hai cạnh của Vsẽ luôn ở cùng một phía của đa giác để chúng được xử lý cùng nhau trong danh sách.)

Mỗi ký tự kết nối hai góc của ô ký tự mà bạn mong đợi (ví dụ trên cùng bên trái và trên cùng bên phải trong trường hợp V).

Một ví dụ với diện tích 7 ( 1+2+1ở hàng thứ hai và 1+1+1thứ ba):

 _
/ \
V\/

Đầu vào

  • Đầu vào sẽ tạo thành một hình chữ nhật, tức là sẽ có cùng số lượng ký tự giữa các dòng mới.
  • Có thể có thêm khoảng trắng ở bất kỳ phía nào của đa giác.
  • Trailing newline là tùy chọn.

Đầu ra

  • Một số nguyên dương duy nhất, diện tích của đa giác.

Ví dụ

Đầu ra là sau hàng cuối cùng của đầu vào của họ.

  _  
  V  

1

/L
\/

3



    /VV\
    L  /
     L/
14

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

32  

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

45

Đây là môn đánh gôn nên bài dự thi ngắn nhất sẽ thắng.


ví dụ thứ ba của bạn phải là 14
Trình tối ưu hóa

@Optimizer Cảm ơn, đã sửa.
ngẫu nhiên

Là sự thiếu ^ chủ ý?
RobAu

@RobAu Vâng, điều đó không đủ tốt.
Randomra

Câu trả lời:


5

CJam, 48 43 29 byte

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

Cập nhật : Chơi gôn rất nhiều bằng toán học và trạng thái * 2 mẹo từ câu trả lời của orlp.

Cách thức hoạt động (Đã lỗi thời, cập nhật sớm)

Chúng tôi phân chia đầu vào trên dòng mới và sau đó cho mỗi phần chúng tôi duy trì một bộ đếm các lần xuất hiện của các ký tự biên L\/. Bộ đếm% 2 này sẽ cho chúng ta biết lựa chọn nào trong hai phân vùng cho tất cả các ký tự. Sau đó, chúng tôi tìm thấy chỉ số của từng ký tự trong chuỗi L _. \/Vsẽ đưa ra -1tham chiếu đến phần tử cuối cùng trong một mảng. Sau khi nhận được chỉ mục, chúng tôi sử dụng 4558Zb2/để tạo mảng [[2 0] [0 2] [0 2] [1 1]]và sau đó chọn chính xác số đếm bằng cách sử dụng bộ đếm.

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

Dùng thử trực tuyến tại đây


22

Bình thường, 47 46 45 36 30

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

Giải trình:

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.

Chúng tôi có hai trạng thái, "trong đa giác" và "ngoài đa giác". Mỗi ký tự sau đây thực hiện các thao tác sau khi đọc chúng từ trên cùng bên trái sang dưới cùng bên phải:

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

Lưu ý rằng "thêm một vào khu vực" và "nếu trong đa giác, thêm hai vào khu vực" là loại trừ lẫn nhau.


Tôi thực sự bối rối về cách làm x=việc. Đây có phải là tài liệu ở đâu đó?
Jakube

@Jakube Đó là nhiệm vụ tăng cường.
orlp

@Jakube Nó giống như +=hoặc *=hoặc bất cứ điều gì. Trong trường hợp xnày đang được sử dụng như xor, vì vậy nó chính xác giống như của Python ^=.
isaacg

14

Võng mạc , 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>

Mỗi dòng đi trong một tệp riêng biệt, vì vậy tôi đã thêm 13 vào số byte. Ngoài ra, bạn có thể đặt tất cả trong một tệp như cũ và sử dụng -scờ. Giá <empty>đỡ cho các tập tin hoặc dòng thực sự trống.

Thật không may, tôi cần 187 byte chỉ để chuyển đổi kết quả từ đơn nguyên sang thập phân. Tôi đoán tôi thực sự nên thực hiện điều này một thời gian sớm .

Giải trình

Retina là một ngôn ngữ dựa trên regex (mà tôi đã viết chính xác để có thể làm những thứ như thế này với regex). Mỗi cặp tệp / dòng xác định một giai đoạn thay thế, với dòng đầu tiên là mẫu và dòng thứ hai là chuỗi thay thế. Các mẫu có thể được đi trước bởi một `chuỗi cấu hình được phân tách, có thể chứa các bộ sửa đổi biểu thức chính quy thông thường, cũng như một số tùy chọn dành riêng cho Retina. Đối với chương trình trên, các tùy chọn có liên quan là; , triệt tiêu đầu ra của giai đoạn đó và+ đó và áp dụng thay thế trong một vòng lặp cho đến khi kết quả dừng thay đổi.

Ý tưởng của giải pháp là đếm từng dòng riêng biệt, bởi vì chúng ta luôn có thể quyết định bởi các ký tự đã gặp dù chúng ta ở trong hay ngoài đa giác. Điều này cũng có nghĩa là tôi có thể nối toàn bộ mọi thứ thành một dòng duy nhất, bởi vì việc bắt đầu và kết thúc một dòng luôn nằm ngoài đa giác. Chúng ta cũng có thể lưu ý rằng _và không gian hoàn toàn giống nhau cho thuật toán quét dòng, cũng như \/. Vì vậy, như một bước đầu tiên tôi thay thế tất cả dòng mới và không gian bằng _và tất cả\ bằng cách /để đơn giản hóa một số mã sau này.

Tôi đang theo dõi trạng thái bên trong / bên ngoài hiện tại với các ký tự io, đồng thời sử dụng is để kiểm đếm khu vực. Để làm như vậy tôi bắt đầu bằng cách đăng ký trướco dòng vào đường nối để đánh dấu rằng chúng ta nằm ngoài đa giác. Tôi cũng đang thêm một iiophần cuối của đầu vào, mà tôi sẽ sử dụng như một tra cứu để tạo các ký tự mới.

Sau đó, sự thay thế lớn đầu tiên chỉ đơn giản là thay thế một ihoặc otheo sau bằng một trong /V_Lcác ký tự tiếp theo, do đó làm ngập và kiểm soát toàn bộ sự việc. Bảng thay thế trông như sau, trong đó các cột tương ứng với ký tự cuối cùng trong dòng đó và các hàng cho ký tự tiếp theo (nơi Sdành cho không gian và <>cho một chuỗi trống). Tôi đã bao gồm tất cả các ký tự của đầu vào để hiển thị các tương đương mà tôi đã sử dụng:

     i     o

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

Lưu ý rằng ký tự cuối cùng sau đó luôn cho biết sau ký tự chúng ta ở bên trong hay bên ngoài đa giác, trong khi số is tương ứng với khu vực cần thêm vào đa giác. Như một ví dụ ở đây là kết quả của bốn lần lặp đầu tiên trên đầu vào ví dụ cuối cùng (điều này được tạo bởi một phiên bản cũ thực sự tràn ngập từng dòng riêng biệt, nhưng nguyên tắc vẫn giống nhau):

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

Cuối cùng, tôi loại bỏ tất cả các os và ngắt dòng bằng cách loại bỏ mọi thứ phù hợp [^i]và phần còn lại là chuyển đổi thập phân sang đơn nhất, khá nhàm chán.


4

Perl, 65 58 byte

map{map{$b^=2*y,/\\L,,;$a+=y,/\\V,,||$b}split//}<>;print$a
  • Chuyển đổi $ b trong khoảng từ 0 đến 2 khi nhìn thấy / \ hoặc L.
  • Thêm 1 đến $ a khi nhìn thấy / \ hoặc V.
  • Thêm $ b vào $ a khi thấy bất cứ điều gì khác.

Giải pháp tốt đẹp, Perl nhỏ gọn đáng ngạc nhiên.
orlp

1
Việc xử lý đầu vào có thể được đơn giản hóa để tăng thêm một số lợi ích:$/=\1;$-^=2*y,/\\L,,,$a+=y,/\\V,,||$-for<>;print$a
nutki

4

GNU sed, 290 + 1

+ 1 là tài khoản cho -r chuyển đổi được chuyển sang sed. Nhận xét và khoảng trắng bổ sung không được tính vào điểm số.

Tôi đã không nhìn rất chi tiết, nhưng tôi nghĩ rằng điều này có lẽ giống với câu trả lời Retina của 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

Tổng quan

  • Thay thế mỗi đơn vị diện tích bằng dấu hai chấm :
  • Đếm số lượng dấu hai chấm

Ghi chú

  • sedđược định hướng theo dòng nên cần một số công việc để xử lý nhiều dòng cùng một lúc. Các Nlệnh thực hiện điều này bằng cách thêm một dòng mới thì dòng bên cạnh không gian mô hình hiện tại. Khó khăn Nlà một khi nó vào luồng đầu vào EOF, nó thoát sedhoàn toàn mà không có tùy chọn nào để xử lý thêm. Để giải quyết vấn đề này, chúng tôi đếm bộ dấu hai chấm hiện tại ở cuối mỗi dòng, ngay trước khi đọc ở dòng tiếp theo.

Đầu ra:

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

3

C, 93 96 108 byte

Chỉnh sửa: Đưa vào các đề xuất tài khoản trong các nhận xét, chuyển đổi thời gian thành một câu lệnh đơn cho vòng lặp và loại bỏ hoàn toàn biến "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);}

Bài gốc:

Đây trông giống như một vấn đề thú vị và đủ đơn giản để cuối cùng tôi có thể tạo một tài khoản ở đây.

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

Văn bản đa giác phải được truyền làm đối số dòng lệnh đầu tiên; điều này sẽ hoạt động với hoặc không có bất kỳ số lượng dòng mới / khoảng trắng.

Điều này chỉ đọc trong một đa giác một ký tự tại một thời điểm, s chuyển đổi cho dù hiện tại trong hay ngoài đa giác trên '/', 'L' hay '\' và t tăng thêm 1 trên '/', 'V', và '\' hoặc bằng 2 nếu bên trong / 0 nếu bên ngoài trên 'L', '_', dấu cách và dòng mới.

Đây là lần đầu tiên tôi thử sức mình với bất kỳ loại "chơi gôn" nào (hoặc C, đến mức nó khác với C ++), vì vậy mọi lời chỉ trích đều được đánh giá cao!


Chào mừng và công việc tốt! Bạn có thể bỏ qua phần i=t=s=0;I nghĩ C khởi tạo tất cả ints thành 0. Ngoài ra, xem nếu bạn có thể biến whilevòng lặp thành một forvòng lặp; mà thường tiết kiệm một vài byte.
Ypnypn

Sử dụng ý tưởng của vòng lặp for ở trên tôi nghĩ bạn có thể làm một cái gì đó như thế này: ...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;...sẽ tiết kiệm được 4 byte; một {, một} và hai;
DaedalusAlpha

Cũng như đã đề cập ở trên, rõ ràng các biến toàn cục được tự động đặt thành 0, vì vậy nếu int i,t,v;được đặt ở phía trước mainthay vì bên trong, chúng ta có thể loại bỏ i=t=s=0hoàn toàn việc tiết kiệm thêm 7 byte.
DaedalusAlpha

3

POSIX sed, 245 244

POSIX sed, không có phần mở rộng hoặc regexps mở rộng. Đầu vào được giới hạn ở kích thước không gian giữ tối đa của sed - POSIX bắt buộc ít nhất 8192; GNU quản lý nhiều hơn. Phiên bản này giả định rằng sẽ không có dòng trống trước hoặc sau hình dạng; thêm 10 byte mã, được chỉ định trong bản mở rộng, có thể đáp ứng điều đó nếu đó là một yêu cầu (câu hỏi ban đầu không chỉ định).

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
}

Mở rộng và chú thích

#!/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;}

Chúng tôi đổi bên bất cứ khi nào chúng tôi nhìn thấy \, /hoặc L; chúng tôi luôn thêm một cho \\, /hoặc V, nhưng thêm 2 (nếu bên trong) hoặc 0 (nếu bên ngoài) cho không gian, dòng mới Lhoặc_ .

Các biến aiđược coi là 0 khi nhập - chúng phải được đặt lại nếu hàm được gọi nhiều lần.

Ung dung:

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

Chương trình kiểm tra:

#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;
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.