Обсяги ящиків ASCII


40

Вступ

У цьому виклику вам надається як вхід ASCII уявлення про сітку (розгорнуту поверхню) прямокутної кубоїди (3D вікно). Формат такий:

....+--+.......
....|##|.......
....|##|.......
....|##|.......
+---+--+---+--+
|###|##|###|##|
+---+--+---+--+
....|##|.......
....|##|.......
....|##|.......
....+--+.......

Кожне обличчя кубоїди - це прямокутник #s, оточений +-|-символами. Зовнішня частина мережі заповнена .s. Мережа завжди матиме однакову орієнтацію: середнє обличчя оточене чотирма сусідніми гранями, а аналог середнього обличчя знаходиться на правій межі входу. Вхід обкладений .s прямокутної форми і не буде містити зайвих рядків або стовпців .s.

Задача

Ваше завдання полягає в тому, щоб взяти як вхідну діаграму, як описано вище, і обчислити об'єм кубоїди, який він представляє, який є лише твором його висоти, ширини та глибини. Ви можете взяти вхід як рядки з обмеженим рядком або масивом рядків.

Довжина кожного краю - це відстань між +-символами на двох його кінцях. Наприклад, горизонтальний край +--+має довжину 3, а вертикальний край

+
|
|
|
+

має довжину 4. Мінімальна довжина ребра дорівнює 1. Приклад кубоїди вище має об'єм 2 * 3 * 4 = 24.

Правила та оцінка

Ви можете написати повну програму або функцію, і найнижча кількість байтів виграє.

Тестові справи

.++..
+++++
+++++
.++..
1

...++....
...||....
...||....
+--++--++
+--++--++
...||....
...||....
...++....
3

..+-+....
..|#|....
+-+-+-+-+
|#|#|#|#|
|#|#|#|#|
+-+-+-+-+
..|#|....
..+-+....
12

.+---+.....
++---++---+
||###||###|
||###||###|
||###||###|
++---++---+
.+---+.....
16

....++.....
....||.....
....||.....
....||.....
+---++---++
|###||###||
|###||###||
|###||###||
+---++---++
....||.....
....||.....
....||.....
....++.....
16

...+--+......
...|##|......
...|##|......
+--+--+--+--+
|##|##|##|##|
+--+--+--+--+
...|##|......
...|##|......
...+--+......
18

....+--+.......
....|##|.......
....|##|.......
....|##|.......
+---+--+---+--+
|###|##|###|##|
+---+--+---+--+
....|##|.......
....|##|.......
....|##|.......
....+--+.......
24

....+-----+..........
....|#####|..........
....|#####|..........
....|#####|..........
+---+-----+---+-----+
|###|#####|###|#####|
|###|#####|###|#####|
|###|#####|###|#####|
|###|#####|###|#####|
+---+-----+---+-----+
....|#####|..........
....|#####|..........
....|#####|..........
....+-----+..........
120

13
Мені дуже подобається цей виклик. Оскільки вхід має стільки зайвої структури, існує багато варіантів, як відновити розміри.
xnor

Відповіді:


25

Сітківка , 29 28 байт

T`.p`xy`\G\..+¶
xy

¶\|
$`
y

Спробуйте в Інтернеті!

У Retina існує багато способів наблизитись до цього, залежно від того, яку область ви хочете помножити на яку сторону, тому я не впевнений, наскільки це оптимально, але насправді це вже набагато коротше, ніж я думав, що це буде.

Наразі у мене є два інших рішення за той самий підрахунок байтів, які здаються дещо голішнішими, ніж вищезазначений підхід:

\G\..+¶

¶\|
$'¶
G`\.
T`.|+

¶\||\+¶\.\D+
$'¶
G`\.
T`.|+

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

І ще одна, все ще на 28 байт (ця насправді множує три сторони замість того, щоб помножувати одну область на сторону):

\G\.
x
-(?<=^.+)
$`
¶\|
$`
x

Пояснення

Основна ідея - помножити площу обличчя зверху на довжину вертикальної сторони, яка торкається межі довжини вводу.

Я буду використовувати такий приклад як приклад (він має довжину сторін 2, 3 і 4, тому площа 24):

...+---+.......
...|###|.......
...|###|.......
+--+---+--+---+
|##|###|##|###|
+--+---+--+---+
...|###|.......
...|###|.......
...+---+.......

Етап 1: Транслітерат

T`.p`xy`\G\..+¶

Режекс \G\..+¶відповідає рядку, який починається з .і безпосередньо примикає до попереднього рядка. Отже, це відповідає всім рядкам, які містять верхню частину обличчя. Сама сцена перетворюється .на xвсіх інших персонажів (будь-яких |+-#) y. Це дає нам такий результат:

xxxyyyyyxxxxxxx
xxxyyyyyxxxxxxx
xxxyyyyyxxxxxxx
+--+---+--+---+
|##|###|##|###|
+--+---+--+---+
...|###|.......
...|###|.......
...+---+.......

Тут є ще один стовпець, yніж нам потрібно представити область верхньої грані. Ми це фіксуємо наступним етапом.

2 етап: замінити

xy

Таким чином, ми узгоджуємо а, yякому передує знак x(який є саме одним з них у кожному рядку) і видаляємо їх обидва з рядка. Ми отримуємо це:

xxyyyyxxxxxxx
xxyyyyxxxxxxx
xxyyyyxxxxxxx
+--+---+--+---+
|##|###|##|###|
+--+---+--+---+
...|###|.......
...|###|.......
...+---+.......

Тепер ми отримали область верхньої грані, представлену числом ys.

3 етап: замінити

¶\|
$`

Наша мета тут - помножити цю область Aна пропущену бічну довжину, яка є числом |на початку рядка плюс 1. Однак насправді простіше помножити на число, n+1оскільки у нас вже є одна копія Aв рядку . Якщо ми замінимо nречі A, ми закінчимо n+1копіями A. Це набагато полегшує нам речі.

Таким чином, ми просто замінюємо будь-який |одразу після виходу на лінійку всім перед матчем. Це обманює рядок досить багато і робить її трохи більшим, ніж нам потрібно, але кількість ys закінчується результатом, який ми шукаємо:

xxyyyyxxxxxxx
xxyyyyxxxxxxx
xxyyyyxxxxxxx
+--+---+--+---+xxyyyyxxxxxxx
xxyyyyxxxxxxx
xxyyyyxxxxxxx
+--+---+--+---+##|###|##|###|
+--+---+--+---+
...|###|.......
...|###|.......
...+---+.......

Етап 4: Матч

y

Залишилося лише порахувати число ys, яке друкується у вигляді десяткового числа наприкінці.


15

Python 2, 57 байт

lambda l:l[0].find('+')*~l[0].count('-')*~`l`.count("'|")

Функція, яка містить список рядків.

Визначає 3 розміри окремо:

l[0].find('+')
Індекс першого +в першому рядку.

-~l[0].count('-')
Кількість -знаків у першому ряду.

~`l`.count("'|")
Кількість рядків, що починаються з |символу, через рядкове представлення списку, що містить перед собою символ лапки.


62 байти:

def f(l):a=l[0].find('+');print(len(l[0])/2-a)*(len(l)-a+~a)*a

Функція, яка містить список рядків і друкує результат.

Знаходить один вимір aяк індекс +у першому рядку. Інші два розміри випливають із нього та ширину та висоту вхідного прямокутника.

63-байтова альтернатива, знаходячи розміри окремо:

lambda l:l[0].find('+')*~l[0].count('-')*~zip(*l)[0].count('|')

11

Bash + coreutils, 83, 77 байт

ЗМІНИ:

  • Збережено 6 байтів, використовуючи "Here String" та трохи оптимізувавши регулярне вираження

Гольф

bc<<<`sed -rn '1{s/(.+)[^\.]*\1/(0\1)*(0/
s/\./+1/gp;a)*(-1
}
/^[+|]/a+1
'`\)

Пояснив

Перетворити з sed :

....+--+....... => (0+1+1+1+1)*(0+1+1+1 )*(-2 +1
. =>()
. =>()
. =>()
. =>()
+ => +1
| => +1
+ => +1
. =>()
. =>()
. =>()
. =>()

Позбудьтесь нових рядків за допомогою зворотних посилань, додайте)

=> (0+1+1+1+1)*(0+1+1+1 )*(-2 +1 +1 +1 +1)

Подайте отриманий вираз до bc

=> 24

Тест

./box <<EOF
.++..
+++++
+++++
.++..
EOF

1

./box <<EOF
...++....
...||....
...||....
+--++--++
+--++--++
...||....
...||....
...++....
EOF

3

./box <<EOF
....+--+.......
....|##|.......
....|##|.......
....|##|.......
+---+--+---+--+
|###|##|###|##|
+---+--+---+--+
....|##|.......
....|##|.......
....|##|.......
....+--+.......
EOF

24

Спробуйте в Інтернеті! (використовує арифметичне розширення bash замість bc , оскільки останній недоступний)


10

Равлики , 19 байт

AM
=~d^.+\+.+l.+^.2

Спробуйте в Інтернеті.

Ідея полягає в тому, що ми починаємо десь із самого правого краю в мережі, а потім їдемо кудись із самого нижнього обличчя. Довжина ребра і площа обличчя множать на механізм підрахунку всіх узгоджуючих шляхів.

AM   ,, A -> count all matching paths
     ,, M -> first char matched is the one in the current direction
     ,,      from the starting location, rather than directly on it
=~          ,, check that we are on the right edge of the grid
d ^.+ \+    ,, go down, matching one or more non-'.' characters, then a '+'
.+          ,, go down one or more times
l .+        ,, go left one or more times
^. 2        ,, match two further characters which aren't '.' to the left

4

JavaScript (ES6), 67 91

s=>(a=~-s.search`
`/2-(b=s.indexOf`+`))*b*(s.split`
`.length-1-2*b)

Тест

F=
s=>(a=~-s.search`
`/2-(b=s.indexOf`+`))*b*(s.split`
`.length-1-2*b)

out=x=>O.textContent+=x+'\n\n'

;`.++..
+++++
+++++
.++..
1

...++....
...||....
...||....
+--++--++
+--++--++
...||....
...||....
...++....
3

..+-+....
..|#|....
+-+-+-+-+
|#|#|#|#|
|#|#|#|#|
+-+-+-+-+
..|#|....
..+-+....
12

.+---+.....
++---++---+
||###||###|
||###||###|
||###||###|
++---++---+
.+---+.....
16

....++.....
....||.....
....||.....
....||.....
+---++---++
|###||###||
|###||###||
|###||###||
+---++---++
....||.....
....||.....
....||.....
....++.....
16

...+--+......
...|##|......
...|##|......
+--+--+--+--+
|##|##|##|##|
+--+--+--+--+
...|##|......
...|##|......
...+--+......
18

....+--+.......
....|##|.......
....|##|.......
....|##|.......
+---+--+---+--+
|###|##|###|##|
+---+--+---+--+
....|##|.......
....|##|.......
....|##|.......
....+--+.......
24

....+-----+..........
....|#####|..........
....|#####|..........
....|#####|..........
+---+-----+---+-----+
|###|#####|###|#####|
|###|#####|###|#####|
|###|#####|###|#####|
|###|#####|###|#####|
+---+-----+---+-----+
....|#####|..........
....|#####|..........
....|#####|..........
....+-----+..........
120`
.split('\n\n').forEach(t=>{
  t=t.split('\n')
  k=+t.pop()
  t=t.join('\n')
  v=F(t)
  out(v+' '+k +' '+(v==k?'OK':'KO')+'\n'+t)
})
<pre id=O></pre>


3

Рубі, 44

Працює за аналогічним принципом з іншими відповідями: знайдіть першу, +щоб знайти глибину, знайдіть наступну .після, +щоб знайти ширину, і порахуйте число |в кінці рядка та додайте 1, щоб знайти висоту.

->s{(s=~/\+/)*($'=~/\./)*s.split("|
").size}

unolfolf у тестовій програмі

f=->s{(s=~/\+/)*    # index of first match of /\+/ in s
($'=~/\./)*         # $' is a special variable, contains string to right of last match. index of /\./ in $' 
s.split("|
").size}            # split the string at |\n to form an array and count the members

puts f[".++..
+++++
+++++
.++.."]

puts f["...++....
...||....
...||....
+--++--++
+--++--++
...||....
...||....
...++...."]

#etc.

3

05AB1E , 21 байт

Нехай Wі Hбудуть відповідно ширина і висота вводу - не коробка. Тоді розміри коробки A, Bі Cдотримуватись наступних правил:

W = 2(A+C)+1
H = B+2C+1

На наступному малюнку показано, що таке A, Bі що Cстосується назв ребер:

....AAAA.......
....|##|.......
....|##|.......
....|##|.......
B---+--CCCCC--+
B###|##|###|##|
B---+--+---+--+
....|##|.......
....|##|.......
....|##|.......
....+--+.......

Звідси наведені вище формули. Ця програма обчислює A, виводить значення Bі Cта , нарешті , обчислює їх продукт.

S'.ÊO<D¹g<;-(D·|g-()P

S'.Ê                  From each character of the first line, yield 0 if it is '.' or 1 otherwise. The result is stored in an array
    O<D               A = sum(array) - 1
       ¹g<;-(D        C = (W-1)/2 - A
              ·|g-(   B = H-1-2*C
                   )  Yield [A,C,B]
                    P Take the product and implicitly display it

Спробуйте в Інтернеті!

Колишня версія - Різний підхід - 26 байт

|vyS'.Ê})¬O<sø¬O<s€O¬Ê1k)P

|                          Take the input as an array of lines (strings)
 vy                        For each line
   S'.Ê                    For each character in the line, yield 0 if it is '.' or 1 otherwise
       }                   End For
        )                  Wrap the results as an array
         ¬O<               A = sum(first_line) - 1
            sø             Transpose the box pattern
              ¬O<          B = sum(first_line) - 1 ; since the pattern is transposed, it corresponds to the first column
                 s€O       Sum every line from the transposed pattern
                    ¬Ê1k   C = index of the first line that has a different sum from the first line
                        )  Yield [A, B, C]
                         P Take the product A*B*C and implicitly display it

2

Befunge 93 , 56 байт

~2%#^_1+
  @.*+<
`"z"~<|:`~0+
5*\`#^_\1>*\~7
%2~\<\+1_^#

Спробуйте в Інтернеті!

Пояснення:

Об'єм поля можна обчислити, помноживши кількість .s на першому рядку перед будь-якими іншими символами, на кількість +і -s в першому рядку - 1, і кількість рядків, що починаються з |+ 1.

~2%#^_1+         Uses the ASCII value % 2 of a character to count the .s

%2~\<\+1_^#      IP wraps around to the bottom. Counts the non . chars
                 Works because ("+" % 2) == ("-" % 2) == 1

5*\`#^_\1>*\~7   Multiplies the previous 2 results and cycles through
                 characters until it hits a newline or EOF

`"z"~<|:`~0+     Adds 1 to the 3rd dimension if the following char is a "|"
                 Also checks for EOF; If there is more input, goes back to
                 previous line. Otherwise, goes to the last line

  @.*+<          Adds 1 to the 3rd dimension, multiplies it to the rest,
                 prints the volume, and ends the program

Мені довелося переміщати лінії IP вгору, а не вниз, щоб використовувати вертикаль, якщо в 3-му рядку. Якщо IP йде по низхідній лінії, вертикальна, якщо при натисканні на наступну горизонтальну лінію вершини стека буде дорівнює 1, посилаючи її в неправильному напрямку.


2

Haskell, 64 56 байт

f(x:r)=sum$fst(span(>'+')x)>>[1|'|':_<-"|":r,'-'<-'-':x]

Спробуйте в Інтернеті!

Пояснення

Очікується, що вхід буде переліком рядків для кожного рядка, тому в fпараметрі xє перший рядок і rсписок рядків, що залишилися.

  1. fst(span(>'+')x)повертає .-префікс першого рядка у вигляді рядка, таким length(fst(span(>'+')x))є і перший вимір d1.
  2. Розуміння списку може діяти як фільтр, наприклад, ['-' | '-' <- x]повертає рядок всіх -у першому рядку, тому 1 + length['-' | '-' <- x]отримує другий вимір d2.
  3. Аналогічно кількість |у першому рядку можна підрахувати, так само 1 + length['|' | '|':_ <- r]це і третій вимір d3.

Зрозуміння списків 2. і 3. можна скоротити до 1+sum[1|'-'<-x]і 1+sum[1|'|':_<-r]скласти список таких для кожного виникнення "-" або "|" а потім взяти суму. Далі ми можемо поставити зовнішнє 1+в списку розуміння, додаючи -до xі "|"до rз отриманням sum[1|'-'<-'-':x]і sum[1|'|':_<-"|":r]. Тепер ми можемо поєднати обидва розуміння списку, поставивши обидва предикати в одне і те ж розуміння: sum[1|'|':_<-"|":r,'-'<-'-':x]зручно, це обчислює саме добуток двох вимірів, оскільки для списків Fта Gнаступного розуміння списків є декартовий продукт F x G =[(a,b)|a<-F,b<-G].

Нарешті, замість множення 1. із комбінацією 2. та 3. ми можемо скористатися >>оператором у списках: F>>Gповторює G length Fрази та конкатує результат. Так fst(span(>'+')x)>>[1|'|':_<-"|":r,'-'<-'-':x]повторює список d2*d3Ones d1раз, отримуючи список d1*d2*d3тих , які потім сумуються , щоб отримати обсяг.


Ви можете вважати вхід списком рядків, усуваючи необхідність lines.
Згарб

@Zgarb Дякую, це економить кілька байт.
Лайконі

1

Java 8, 185 129 байт

завдяки Згарбу за -56 байт

гольф:

int g(String[]i){int h=0;for(String k:i){if(k.charAt(0)=='.')h++;else break;}return((i[0].length()-2*h-1)/2)*(i.length-2*h-1)*h;}

неозорений:

int g(String[] i) {
    int h = 0;
    for (String k : i) {
        if (k.charAt(0) == '.') h++;
        else break;
    }
    return ((i[0].length()-2*h-1)/2)*(i.length-2*h-1)*h;
}

Пояснення

a*b*h = ((length_of_line-2*h-1)/2)*(number_of_lines-2*h-1)*h

де aі bрозміри основи і hвисота. Ви можете знайти h, порахувавши перші hрядки, де ви починаєте з а ..


Ви можете приймати вхід як масив або рядки, тому не потрібно вручну ділити його.
Згарб

oops thx, виправляючи це ...
Bobas_Pett

1

Java, 112 байт

int v(String[]s){int a=s[0].lastIndexOf('+')-s[0].indexOf('+'),b=s[0].length()/2-a;return a*b*(s.length-2*b-1);}

Розширено:

int v(String[] s)
{
  // length of the edge in the first line
  int a = s[0].lastIndexOf('+') - s[0].indexOf('+');
  // length of the second edge
  // int b = s[0].length() - 2 * a - 1; <-- multiplied by 2
  int b = s[0].length()/2 - a; // <-- hack, length is always odd
  // length of the third edge in ()
  // volume
  return a * b * (s.length - 2 * b - 1);
} // end method v

1

Powershell, 68 67 байт

($c="$args"|% i*f +)*($args[0].Length/2-.5-$c)*($args.Count-1-2*$c)

Примітка: "$args"|% i*f + це ярлик для"$args".indexOf('+')

Пояснення

Хороше пояснення випливає з відповіді Osable :

Нехай Wі Hбудуть відповідно ширина і висота вводу - не коробка. Тоді розміри коробки A, Bі Cдотримуватись наступних правил:

W = 2(A+C)+1
H = B+2C+1

На наступному малюнку показано, що таке A, Bі що Cстосується назв ребер:

CCCCAAAA.......
....|##|.......
....|##|.......
....|##|.......
B---+--+---+--+
B###|##|###|##|
B---+--+---+--+
....|##|.......
....|##|.......
....|##|.......
....+--+.......

І Cє позицією першого +в першому рядку вводу.

Тестовий сценарій:

$f = {

($c="$args"|% i*f +)*($args[0].Length/2-.5-$c)*($args.Count-1-2*$c)

}

@(

,(1, ".++..",
     "+++++",
     "+++++",
     ".++..")

,(3,"...++....",
    "...||....",
    "...||....",
    "+--++--++",
    "+--++--++",
    "...||....",
    "...||....",
    "...++....")

,(12,"..+-+....",
     "..|#|....",
     "+-+-+-+-+",
     "|#|#|#|#|",
     "|#|#|#|#|",
     "+-+-+-+-+",
     "..|#|....",
     "..+-+....")

,(16,".+---+.....",
     "++---++---+",
     "||###||###|",
     "||###||###|",
     "||###||###|",
     "++---++---+",
     ".+---+.....")

,(16,"....++.....",
     "....||.....",
     "....||.....",
     "....||.....",
     "+---++---++",
     "|###||###||",
     "|###||###||",
     "|###||###||",
     "+---++---++",
     "....||.....",
     "....||.....",
     "....||.....",
     "....++.....")

,(18,"...+--+......",
     "...|##|......",
     "...|##|......",
     "+--+--+--+--+",
     "|##|##|##|##|",
     "+--+--+--+--+",
     "...|##|......",
     "...|##|......",
     "...+--+......")


,(24,"....+--+.......",
     "....|##|.......",
     "....|##|.......",
     "....|##|.......",
     "+---+--+---+--+",
     "|###|##|###|##|",
     "+---+--+---+--+",
     "....|##|.......",
     "....|##|.......",
     "....|##|.......",
     "....+--+.......")

,(120,"....+-----+..........",
      "....|#####|..........",
      "....|#####|..........",
      "....|#####|..........",
      "+---+-----+---+-----+",
      "|###|#####|###|#####|",
      "|###|#####|###|#####|",
      "|###|#####|###|#####|",
      "|###|#####|###|#####|",
      "+---+-----+---+-----+",
      "....|#####|..........",
      "....|#####|..........",
      "....|#####|..........",
      "....+-----+..........")

) | % {
    $expected,$s = $_
    $result = &$f @s
    "$($result-eq$expected): $result"
}

Вихід:

True: 1
True: 3
True: 12
True: 16
True: 16
True: 18
True: 24
True: 120

0

Мова Вольфрама (Mathematica) , 64 байти

(2(x=#@"
")-(y=#@"|")-9)((9-5x+y)^2-9#@".")/54&@*CharacterCounts

Спробуйте в Інтернеті!

Використовує число ., |і \nсимволи у вхідних даних , щоб вирішити для обсягу. Це виглядає нерозумно, бо натомість є фактично новий рядок \n.

Якщо A, Bі Cє сторони, то . = 2C(A+2C), | = 5B+4C-9і \n = B+2C, тож ми можемо вирішити для гучності ABCз точки зору цих трьох символів.

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