Объемы ASCII ящиков

40

Введение

В этом задании в качестве входных данных вам дается ASCII-представление сети (развернутой поверхности) прямоугольного кубоида (3D-прямоугольника). Формат такой:

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

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

Задание

Ваша задача - взять в качестве входных данных диаграмму, описанную выше, и вычислить объем кубоида, который он представляет, который является просто произведением его высоты, ширины и глубины. Вы можете принять входные данные как строку с разделителями новой строки или массив строк.

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

+
|
|
|
+

имеет длину 4. Минимальная длина ребра равна 1. Приведенный выше пример кубоида имеет объем 2 * 3 * 4 = 24.

Правила и оценки

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

Контрольные примеры

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

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

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

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

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

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

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

....+-----+..........
....|#####|..........
....|#####|..........
....|#####|..........
+---+-----+---+-----+
|###|#####|###|#####|
|###|#####|###|#####|
|###|#####|###|#####|
|###|#####|###|#####|
+---+-----+---+-----+
....|#####|..........
....|#####|..........
....|#####|..........
....+-----+..........
120
Zgarb
источник
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

Таким образом, мы сопоставляем a y, которому предшествует an 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('|')
XNOR
источник
11

Bash + coreutils, 8377 байт

правок:

  • Сохранено 6 байт, используя «Here String» и немного оптимизируя регулярное выражение

Golfed

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

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

дирижабль
источник
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
feersum
источник
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>

edc65
источник
3

Руби, 44

Работает по принципу, аналогичному другим ответам: найдите первый, +чтобы найти глубину, найдите следующий .после, +чтобы найти ширину, и посчитайте число |в конце строки и добавьте 1, чтобы найти высоту.

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

разряженный в тестовой программе

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.
Уровень реки St
источник
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
Osable
источник
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 шел вниз по линии, вертикальная if заставила бы вершину стека быть равной 1 при попадании в следующую горизонтальную if, отправляя его в неправильном направлении.

MildlyMilquetoast
источник
2

Haskell, 64 56 байт

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

Попробуйте онлайн!

объяснение

Предполагается, что входными данными будет список строк для каждой строки, поэтому в fпараметре xнаходится первая строка и rсписок оставшихся строк.

  1. fst(span(>'+')x)возвращает .-prefix первой строки в виде строки, 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тех , которые затем суммируются , чтобы получить объем.

Laikoni
источник
Вы можете принять входные данные в виде списка строк, избавляя от необходимости lines.
Згарб
@Zgarb Спасибо, это экономит несколько байтов.
Лайкони
1

Java 8, 185 129 байт

спасибо Згарбу за -56 байт

golfed:

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

ungolfed:

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строки, где вы начинаете с ..

Bobas_Pett
источник
Вы можете принимать входные данные в виде массива или строк, поэтому нет необходимости разбивать их вручную.
Згарб
ой, спасибо, исправляя это ...
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);}

Expanded:

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
Mazzy
источник
0

Wolfram Language (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с точки зрения этих трех символов.

Миша лавров
источник