ASCII多边形的面积


31

您应该编写一个程序或函数,该程序或函数接收代表ascii-art多边形的字符串作为输入并输出,否则将返回多边形的面积。

输入是由字符组成_ / \ L V spacenewline定义简单多边形的字符串(这意味着没有多余的段,没有自触和没有自相交)。

单个字符单元格的面积为 2

  • _将单元格拆分为大小,0然后2
  • \将单元格拆分为大小,1然后1
  • /将单元格拆分为大小,1然后1
  • L将单元格拆分为大小,0然后2
  • V将单元格拆分为大小,1并且1(的两侧V将始终位于多边形的同一侧,因此在列表中将它们一起处理。)

每个字符都连接您期望的字符单元格的两个角(例如,如果是,则为左上角和右上角V)。

面积为7的示例(1+2+1第二行和1+1+1第三行):

 _
/ \
V\/

输入值

  • 输入将形成一个矩形,即换行符之间将有相同数量的字符。
  • 多边形的任何一侧都可以有多余的空格。
  • 尾随换行符是可选的。

输出量

  • 一个正整数,即多边形的面积。

例子

输出在其输入的最后一行之后。

  _  
  V  

1

/L
\/

3



    /VV\
    L  /
     L/
14

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

32  

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

45

这是代码高尔夫球,因此最短的条目将获胜。


您的第三个示例应为14
Optimizer

@Optimizer谢谢,已更正。
randomra 2015年

^ 故意缺乏吗?
RobAu

@RobAu是的,看起来还不够好。
randomra

Answers:


5

CJam,48 43 29字节

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

更新:使用数学和orlp的答案中的state * 2技巧打了很多球。

工作原理(已过时,即将更新)

我们在换行符上分割输入,然后对于每个部分,我们维护一个边界字符出现计数器L\/。计数器%2将告诉我们要为所有字符选择两个分区中的哪个分区。然后我们找到字符串中每个字符的索引L _\/V-1引用数组中的最后一个元素。获取索引后,我们使用4558Zb2/创建数组[[2 0] [0 2] [0 2] [1 1]],然后使用计数器选择正确的计数。

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

在这里在线尝试


22

Pyth,47 46 45 36 30

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

说明:

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.

我们有两个状态,“处于多边形中”和“处于多边形外”。从左上角到右下角阅读以下字符时,每个字符都将执行以下操作:

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

注意“将一个添加到区域”和“如果在多边形中,将两个添加到区域”是互斥的。


I'm really confused on how x= works. Is this documented somewhere?
Jakube

@Jakube这是扩充作业。
orlp 2015年

@Jakube它像+=*=或什么的。在这种情况下,x它被用作xor,因此它与Python的完全相同^=
isaacg 2015年

14

视网膜,293 + 15 = 308 314 385字节

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

每行都在一个单独的文件中,因此我在字节数上增加了13。或者,您可以将所有内容原样放在一个文件中并使用该-s标志。的<empty>立场实际上是空文件或线路。

Unfortunately, I need 187 bytes just to convert the result from unary to decimal. I guess I really should implement this some time soon.

Explanation

Retina is a regex-based language (which I wrote exactly for being able to do stuff like this with regex). Each pair of files/lines defines a replacement stage, with the first line being the pattern and the second line the replacement string. Patterns can be preceded by a `-delimited configuration string, which may contain the usual regex modifiers, as well as some Retina-specific options. For the above program, the relevant options are ;, which suppresses output of that stage and +, which applies the replacement in a loop until the result stops changing.

解决方案的想法是分别计算每行,因为我们始终可以根据遇到的字符来确定我们是在多边形内部还是外部。这也意味着我可以将整个对象连接到一条直线中,因为走线的起点和终点总是在多边形之外。我们还可以注意到,_对于行扫描算法以及\和,and space完全相同/。因此,第一步,我将所有换行符和空格_全部替换为\通过/ to simplify some code later on.

我使用字符i和跟踪当前的内部/外部状态o,同时还使用is来计算区域。为此,我首先o在连接的行之前添加一个,以标记我们在多边形之外。我还将iio在输入的最后添加一个,用作查找以生成新字符。

Then, the first large replacement simply replaces an i or o followed by one of /V_L with the next set of characters, thereby flooding and tallying the entire thing. The replacement table looks as follows, where the columns correspond to the last character in that line and the rows to the next character (where S is for space and <> for an empty string). I've included all characters of the input to show the equivalences I've already made use of:

     i     o

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

请注意,最后一个字符总是指示该字符之后是在多边形内部还是外部,而is 的数量对应于需要添加到多边形中的区域。作为示例,下面是最后一个示例输入的前四个迭代的结果(这是由一个旧版本生成的,该版本实际上分别淹没了每一行,但是原理仍然相同):

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

最后,我只是去除了所有os并通过删除所有匹配的行换行符[^i],其余的是十进制到一进制的转换,这很无聊。


4

Perl,65 58字节

map{map{$b^=2*y,/\\L,,;$a+=y,/\\V,,||$b}split//}<>;print$a
  • 看到/ \或L时,将$ b切换为0到2。
  • 看到/ \或V后,在$ a中加1。
  • 看到其他内容后,将$ b添加到$ a。

不错的解决方案,Perl非常紧凑。
orlp 2015年

1
输入处理可以简化以获得更多收益:$/=\1;$-^=2*y,/\\L,,,$a+=y,/\\V,,||$-for<>;print$a
nutki 2015年

4

GNU sed,290 + 1

+1代表 -r switch passed to sed. Comments and additional whitespace not counted in the score.

我没有详细介绍,但我认为这可能类似于马丁的视网膜答案

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

总览

  • 用冒号替换每个单位区域 :
  • 计算冒号的数量

笔记

  • sed is line oriented so needs some work to process multiple lines at once. The N command does this by appending a newline then the next line to the current pattern space. The difficulty with N is that once it gets to the input stream EOF, it quits sed completely without any option to do further processing. To get around this, we count the current set of colons at the end of each line, just before reading in the next line.

Output:

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

3

C, 93 96 108 bytes

Edit: Took into account suggestions in the comments, converted the while into a single-statement for loop, and removed the "i" variable entirely.

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

Original post:

This looked like a fun and simple enough problem to finally get me to create an account here.

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

The polygon text should be passed as the first command-line argument; this should work with or without any amount of newlines / whitespace.

This just reads in the polygon one character at a time, s switches whether currently in or outside of the polygon on '/', 'L', or '\', and t increases by 1 on '/', 'V', and '\', or by 2 if inside / 0 if outside on 'L', '_', space and newline.

This is my first time trying my hand at any sort of "golfing" (or C, to the extent it differs from C++), so any criticisms are appreciated!


Welcome and good job! You may be able to skip the i=t=s=0; I think C initializes all ints to 0 anyway. Also, see if you can turn the while loop into a for loop; that often saves a few bytes.
Ypnypn

Using the idea of the for loop above I think you can do something like this: ...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;... which should save 4 bytes; one {, one } and two ;
DaedalusAlpha

Also as mentioned above, apparently global variables are automatically set to 0, so if int i,t,v; was to be put in front of main instead of inside we could get rid of i=t=s=0 altogether saving another 7 bytes.
DaedalusAlpha

3

POSIX sed, 245 244

POSIX sed, no extensions or extended regexps. Input is limited to the maximum hold space size of sed - POSIX mandates at least 8192; GNU manages more. This version assumes that there will be no blank lines before or after the shape; an extra 10 bytes of code, indicated in the expansion, can accommodate that if it's a requirement (original question doesn't specify).

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
}

Expanded and annotated

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

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

We switch sides whenever we see \, / or L; we always add one for \\, / or V, but add 2 (if inside) or 0 (if outside) for space, newline, L or _.

The variables a and i are assumed to be zero on entry - they must be reset if the function is to be called more than once.

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;
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.