พื้นที่ของรูปหลายเหลี่ยม ASCII


31

คุณควรเขียนโปรแกรมหรือฟังก์ชั่นที่รับสตริงที่แทนรูปหลายเหลี่ยมแบบ ascii-art เมื่ออินพุตและเอาต์พุต ot ส่งคืนพื้นที่ของรูปหลายเหลี่ยม

อินพุตเป็นสตริงที่ประกอบด้วยอักขระ_ / \ L V spaceและnewlineการกำหนดรูปหลายเหลี่ยมอย่างง่าย (ซึ่งหมายถึงไม่มีเซ็กเมนต์พิเศษไม่มีการแตะด้วยตนเองและไม่มีการตัดกันด้วยตนเอง)

พื้นที่ของเซลล์อักขระเดียวคือ 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 ขอบคุณแก้ไขแล้ว
randomra

ขาด^ ความตั้งใจหรือไม่?
RobAu

@RobAu ใช่ว่ามันดูไม่ดีพอ
randomra

คำตอบ:


5

CJam, 48 43 29 ไบต์

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

อัปเดต : มีจำนวนมากโดยใช้คณิตศาสตร์และกลอุบาย * 2 จากคำตอบของ orlp

มันทำงานอย่างไร (ล้าสมัยอัปเดตเร็ว ๆ นี้)

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

โปรดทราบว่า "เพิ่มหนึ่งในพื้นที่" และ "ถ้าในรูปหลายเหลี่ยมเพิ่มสองไปยังพื้นที่" เป็นพิเศษร่วมกัน


ฉันสับสนในการx=ทำงาน เอกสารนี้อยู่ที่ไหนสักแห่ง?
Jakube

@Jakube มันเพิ่มการมอบหมาย
orlp

@Jakube มันเหมือน+=หรือ*=หรืออะไรก็ตาม ในกรณีนี้จะถูกใช้เป็นแฮคเกอร์จึงเป็นเหมือนกับงูใหญ่x ^=
isaacg

14

Retina , 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>ยืนสำหรับไฟล์ที่ว่างเปล่าจริงหรือเส้น

น่าเสียดายที่ฉันต้องการ 187 ไบต์เพียงเพื่อแปลงผลลัพธ์จากนารี่เป็นทศนิยม ฉันคิดว่าฉันควรจริง ๆดำเนินการนี้บางเวลาเร็ว ๆ นี้

คำอธิบาย

Retina เป็นภาษาที่ใช้ regex (ซึ่งฉันเขียนไว้อย่างชัดเจนว่าสามารถทำสิ่งนี้ได้ด้วย regex) แต่ละคู่ของไฟล์ / บรรทัดกำหนดขั้นตอนการเปลี่ยนโดยบรรทัดแรกเป็นรูปแบบและบรรทัดที่สองคือสตริงการแทนที่ รูปแบบสามารถนำหน้าด้วย`สตริงการกำหนดค่า -delimited ซึ่งอาจมีตัวดัดแปลง regex ปกติรวมถึงตัวเลือกเฉพาะสำหรับ Retina บางตัว สำหรับโปรแกรมข้างต้นตัวเลือกที่เกี่ยวข้องคือ;ซึ่งจะหยุดการแสดงผลของขั้นตอนนั้นและ+ใช้การแทนที่ในลูปจนกว่าผลลัพธ์จะหยุดการเปลี่ยนแปลง

แนวคิดของการแก้ปัญหาคือการนับแต่ละบรรทัดแยกกันเพราะเราสามารถตัดสินใจโดยตัวละครที่พบอยู่แล้วไม่ว่าเราจะอยู่ภายในหรือภายนอกรูปหลายเหลี่ยม นี่ก็หมายความว่าฉันสามารถรวมสิ่งทั้งหมดเข้าด้วยกันเป็นเส้นเดียวเพราะการเริ่มต้นและจุดสิ้นสุดของเส้นนั้นอยู่นอกรูปหลายเหลี่ยมเสมอ นอกจากนี้เรายังสามารถทราบว่า_และพื้นที่จะสมบูรณ์เหมือนกันสำหรับขั้นตอนวิธีเส้นกวาดเช่นเดียวกับและ\ /ดังนั้นในขั้นตอนแรกฉันจะแทนที่บรรทัดใหม่และช่องว่าง_ทั้งหมดและทั้งหมด\โดย/การลดความซับซ้อนโค้ดบางส่วนในภายหลัง

ฉันกำลังติดตามสถานะภายใน / ภายนอกปัจจุบันด้วยตัวละครiและoในขณะเดียวกันก็ใช้is เพื่อนับพื้นที่ ในการทำเช่นนั้นฉันเริ่มต้นด้วยการเติมoเพิ่มบรรทัดที่เข้าร่วมเพื่อทำเครื่องหมายว่าเราอยู่นอกรูปหลายเหลี่ยม ฉันยังเพิ่มiioส่วนท้ายของอินพุตซึ่งฉันจะใช้เป็นเครื่องมือค้นหาเพื่อสร้างตัวละครใหม่

จากนั้นการแทนที่ครั้งใหญ่ครั้งแรกจะแทนที่iหรือoตามด้วยหนึ่ง/V_Lในชุดอักขระถัดไปซึ่งจะทำให้น้ำท่วมและรับทราบเรื่องราวทั้งหมด ตารางการแทนที่มีลักษณะดังต่อไปนี้โดยที่คอลัมน์สอดคล้องกับอักขระตัวสุดท้ายในบรรทัดนั้นและแถวไปยังอักขระถัดไป (โดยที่Sสำหรับช่องว่างและ<>สำหรับสตริงว่าง) ฉันได้รวมอักขระทั้งหมดของอินพุตเพื่อแสดงความเท่าเทียมที่ฉันได้ใช้ไปแล้ว:

     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

สุดท้ายนี้ฉันจะกำจัดตัวแบ่งทั้งหมดoและตัวแบ่งบรรทัดโดยการลบทุกอย่างที่ตรงกัน[^i]และส่วนที่เหลือคือการแปลงแบบทศนิยมเป็น unary ซึ่งค่อนข้างน่าเบื่อ


4

Perl, 65 58 ไบต์

map{map{$b^=2*y,/\\L,,;$a+=y,/\\V,,||$b}split//}<>;print$a
  • สลับ $ b ระหว่าง 0 ถึง 2 เมื่อเห็น / \ หรือ L
  • เพิ่ม 1 ถึง $ a เมื่อเห็น / \ หรือ V.
  • เพิ่ม $ b เป็น $ a เมื่อเห็นสิ่งอื่น

ทางออกที่ดี Perl มีขนาดกะทัดรัดน่าแปลกใจ
orlp

1
การประมวลผลข้อมูลเข้าสามารถทำให้ง่ายขึ้นเพื่อผลประโยชน์เพิ่มเติม:$/=\1;$-^=2*y,/\\L,,,$a+=y,/\\V,,||$-for<>;print$a
nutki

4

GNU sed, 290 + 1

+1 คือบัญชีสำหรับ -rสวิตช์ที่ส่งผ่านไปยัง sed ความคิดเห็นและช่องว่างเพิ่มเติมไม่นับรวมอยู่ในคะแนน

ฉันไม่ได้ดูรายละเอียดมาก แต่ฉันคิดว่านี่อาจจะคล้ายกับคำตอบของ 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

ภาพรวม

  • แทนที่แต่ละหน่วยของพื้นที่ด้วยโคลอน :
  • นับจำนวนโคลอน

หมายเหตุ

  • sedเป็นบรรทัดที่มุ่งเน้นดังนั้นต้องการงานบางอย่างในการประมวลผลหลายบรรทัดในครั้งเดียว Nคำสั่งไม่นี้โดยท้ายบรรทัดใหม่แล้วบรรทัดถัดไปยังพื้นที่รูปแบบปัจจุบัน ปัญหาNก็คือเมื่อได้รับกระแส EOF แล้วมันจะหยุดทำงานsedอย่างสมบูรณ์โดยไม่มีตัวเลือกใด ๆ ในการประมวลผลเพิ่มเติม ในการหลีกเลี่ยงปัญหานี้เราจะนับชุดโคลอนปัจจุบันที่จุดสิ้นสุดของแต่ละบรรทัดก่อนที่จะอ่านในบรรทัดถัดไป

เอาท์พุท:

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

3

C, 93 96 108ไบต์

แก้ไข:เข้าสู่การแนะนำบัญชีในความคิดเห็นแปลง while เป็นคำสั่งเดียวสำหรับลูปและลบตัวแปร "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);}

โพสต์ต้นฉบับ:

นี่เป็นปัญหาที่สนุกและเรียบง่ายพอที่จะทำให้ฉันสร้างบัญชีได้ที่นี่

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

ข้อความรูปหลายเหลี่ยมควรถูกส่งผ่านเป็นอาร์กิวเมนต์บรรทัดคำสั่งแรก สิ่งนี้ควรทำงานโดยมีหรือไม่มีบรรทัดใหม่ / ช่องว่างจำนวนเท่าใดก็ได้

นี่เป็นการอ่านในรูปหลายเหลี่ยมทีละตัวอักษร s จะสลับว่าในหรือนอกรูปหลายเหลี่ยมบน '/', 'L' หรือ '\' และ t เพิ่มขึ้น 1 เมื่อ '/', 'V' และ '\' หรือ 2 ถ้าภายใน / 0 ถ้าอยู่ข้างนอกใน 'L', '_', ช่องว่างและขึ้นบรรทัดใหม่

นี่เป็นครั้งแรกที่ฉันลองใช้มือกับการตีกอล์ฟ (หรือ C) ในระดับที่แตกต่างจาก C ++ ดังนั้นการวิจารณ์ใด ๆ ก็ชื่นชม!


ยินดีต้อนรับคุณและงานที่ดี! คุณอาจจะข้ามi=t=s=0;ฉันคิดว่า C เริ่มต้นทั้งหมดintเป็น 0 ต่อไป ดูว่าคุณสามารถเปลี่ยนwhileลูปเป็นforลูปได้หรือไม่ ที่มักจะบันทึกไม่กี่ไบต์
Ypnypn

ใช้แนวคิดของ for for ด้านบนฉันคิดว่าคุณสามารถทำสิ่งนี้: ...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 ไบต์; หนึ่ง {, หนึ่ง} และสอง
DaedalusAlpha

เช่นเดียวกับที่กล่าวไว้ข้างต้นตัวแปรทั่วโลกจะถูกตั้งค่าเป็น 0 โดยอัตโนมัติดังนั้นหากint i,t,v;จะใส่ไว้ข้างหน้าmainแทนที่จะเข้าไปข้างในเราจะสามารถกำจัดการi=t=s=0บันทึกอีก 7 ไบต์ได้โดยสิ้นเชิง
DaedalusAlpha

3

POSIX รุ่น245 244

POSIX ไม่มีส่วนขยายหรือ regexps ที่ขยายเพิ่ม อินพุตถูก จำกัด ขนาดพื้นที่การพักสูงสุดของ sed - POSIX สั่งอย่างน้อย 8192; GNU จัดการเพิ่มเติม รุ่นนี้อนุมานว่าจะไม่มีเส้นว่างก่อนหรือหลังรูปร่าง รหัสเพิ่มเติม 10 ไบต์ซึ่งระบุไว้ในส่วนขยายสามารถรองรับได้หากเป็นข้อกำหนด (คำถามดั้งเดิมไม่ได้ระบุ)

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
}

ขยายและเพิ่มความคิดเห็น

#!/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 ไบต์

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

เราสลับข้างเมื่อใดก็ตามที่เราเห็น\, /หรือL; เรามักจะเพิ่มหนึ่ง\\, /หรือVแต่เพิ่ม 2 (ถ้าภายใน) หรือ 0 (ถ้านอก) สำหรับพื้นที่ขึ้นบรรทัดใหม่หรือL_

ตัวแปรaและiถือว่าเป็นศูนย์ในรายการ - พวกเขาจะต้องถูกรีเซ็ตถ้าฟังก์ชั่นจะถูกเรียกว่ามากกว่าหนึ่งครั้ง

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

โปรแกรมทดสอบ:

#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;
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.