Площа багатокутника ASCII


31

Вам слід написати програму або функцію, яка отримує рядок, що представляє полігон ascii-art як вхідний, а вихідний з повертає область полігону.

Вхід - це рядок, що складається з символів _ / \ 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

Піта, 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використовується як xor, тому він точно такий же, як і Python ^=.
isaacg

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>Стенд насправді порожні файли або рядки.

На жаль, мені потрібно 187 байт просто для перетворення результату від одинарного до десяткового. Я думаю, що мені справді слід незабаром реалізувати це .

Пояснення

Сітківка - мова на основі регулярних виразів (яку я написав саме для того, щоб вміти робити такі речі за допомогою регексу). Кожна пара файлів / рядків визначає етап заміни, причому перший рядок є візерунком, а другий рядок - рядком заміни. `Шаблонам може передувати конфігурація -делімітована конфігурація, яка може містити звичайні модифікатори регулярних виразів, а також деякі параметри, характерні для 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розривів s та рядків, видаляючи все, що відповідає [^i], а решта - перетворення від десятків до одинарних, яке досить нудне.


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. Коментарі та додаткові пробіли не враховуються.

Я не дуже детально роздивився, але думаю, що це, мабуть, схоже на відповідь Мартіна Ретіна :

:                      # 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 байт

Редагувати: враховував пропозиції в коментарях, перетворював час в цикл для одноразового вилучення та повністю видаляв змінну "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', '_', пробіл та новий рядок.

Це я вперше пробую себе в будь-якому «гольфінгу» (або С, наскільки це відрізняється від С ++), тому будь-яка критика оцінюється!


Ласкаво просимо і добре працюємо! Можливо, ви зможете пропустити, i=t=s=0;я думаю, що C все intодно ініціалізує всі s до 0. Також подивіться, чи можна перетворити whileцикл у forцикл; що часто економить кілька байт.
Ypnypn

Використовуючи ідею циклу 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 sed, 245 244

POSIX sed, без розширень або розширених регулярних виразів. Вхід обмежений максимальним розміром місця утримування 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вважаються нульовими при введенні - вони повинні бути скинуті, якщо функцію потрібно викликати більше одного разу.

Безголовки:

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;
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.