Volumes de caixas ASCII

40

Introdução

Neste desafio, você recebe como representação a representação ASCII da rede (superfície desdobrada) de um cubóide retangular (caixa 3D). O formato é este:

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

Cada face do cubóide é um retângulo de #s cercado por +-|caracteres. A parte externa da rede é preenchida com .s. A rede sempre terá a mesma orientação: há uma face do meio cercada pelas quatro faces vizinhas e a contraparte da face do meio está na borda direita da entrada. A entrada é preenchida com .s para uma forma retangular e não conterá linhas ou colunas extras de .s.

A tarefa

Sua tarefa é tomar como entrada um diagrama como acima e calcular o volume do cubóide que ele representa, que é apenas o produto de sua altura, largura e profundidade. Você pode considerar a entrada como uma sequência delimitada por nova linha ou uma matriz de sequências.

O comprimento de cada aresta é a distância entre os +caracteres em suas duas extremidades. Por exemplo, a borda horizontal +--+tem comprimento 3 e a borda vertical

+
|
|
|
+

tem comprimento 4. O comprimento mínimo de uma aresta é 1. O exemplo cubóide acima tem volume 2 * 3 * 4 = 24.

Regras e pontuação

Você pode escrever um programa completo ou uma função, e a menor contagem de bytes vence.

Casos de teste

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

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

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

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

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

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

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

....+-----+..........
....|#####|..........
....|#####|..........
....|#####|..........
+---+-----+---+-----+
|###|#####|###|#####|
|###|#####|###|#####|
|###|#####|###|#####|
|###|#####|###|#####|
+---+-----+---+-----+
....|#####|..........
....|#####|..........
....|#####|..........
....+-----+..........
120
Zgarb
fonte
13
Eu realmente gosto deste desafio. Como a entrada possui uma estrutura redundante, há muitas opções de como recuperar as dimensões.
Xnor 12/12

Respostas:

25

Retina , 29 28 bytes

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

¶\|
$`
y

Experimente online!

muitas maneiras de abordar isso na Retina, dependendo de qual área você deseja multiplicar com qual lado, por isso não tenho certeza de como isso é ótimo, mas na verdade já é muito mais curto do que eu pensava.

Atualmente, tenho duas outras soluções na mesma contagem de bytes que parecem um pouco mais eficientes do que a abordagem acima:

\G\..+¶

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

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

Embora neles eu possa salvar um byte cada se assumir que a entrada termina com um avanço de linha à direita, mas prefiro não ter que confiar nisso.

E outro, ainda com 28 bytes (na verdade, este multiplica três lados em vez de multiplicar uma área por lado):

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

Explicação

A idéia principal é multiplicar a área da face no topo pelo comprimento do lado vertical que toca a borda de comprimento da entrada.

Usarei a seguinte entrada como exemplo (ela possui comprimentos laterais 2, 3 e 4, portanto, uma área de 24):

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

Etapa 1: Transliterar

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

A regex \G\..+¶corresponde a uma linha que começa com .e é imediatamente adjacente à linha anterior. Portanto, isso corresponde a todas as linhas que contêm a face superior. O palco em si se .transforma xe todos os outros personagens (qualquer um |+-#) em y. Isso nos dá o seguinte resultado:

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

Isso tem mais uma coluna do yque precisamos para representar a área da face superior. Corrigimos isso com o próximo estágio.

Etapa 2: substituir

xy

Então, combinamos um yque é precedido por um x(que é exatamente um deles por linha) e os removemos da string. Temos isso:

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

Então agora temos a área da face superior representada pelo número de ys.

Etapa 3: substituir

¶\|
$`

Nosso objetivo aqui é multiplicar essa área Apelo comprimento do lado que falta, que é o número de |no início de uma linha mais 1. No entanto, é realmente mais fácil multiplicar por um número, n+1porque já temos uma cópia Ana string . Se substituirmos as ncoisas por A, acabaremos com n+1cópias de A. Isso facilita muito as coisas para nós.

Então, simplesmente substituímos qualquer |imediatamente após um avanço de linha por tudo à frente da partida. Isso manipula bastante a string e a torna um pouco maior do que precisamos, mas o número de ys acaba sendo o resultado que estamos procurando:

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

Etapa 4: partida

y

Tudo o que resta é contar o número de ys, que é impresso como um número decimal no final.

Martin Ender
fonte
15

Python 2, 57 bytes

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

Uma função que recebe uma lista de cadeias.

Determina as 3 dimensões separadamente:

l[0].find('+')
O índice do primeiro +na primeira linha.

-~l[0].count('-')
O número de -sinais na primeira linha.

~`l`.count("'|")
O número de linhas que começam com o |símbolo, através da representação em cadeia da lista que possui um símbolo de aspas antes dela.


62 bytes:

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

Uma função que recebe uma lista de cadeias e imprime o resultado.

Localiza uma dimensão acomo o índice de +na primeira linha. As outras duas dimensões são inferidas a partir dele e a largura e altura do retângulo de entrada.

Uma alternativa de 63 bytes, localizando as dimensões separadamente:

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

Bash + coreutils, 83, 77 bytes

EDITAS:

  • Economizou 6 bytes, usando "Here String" e otimizando um pouco a regexp

Golfe

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

Explicado

Transforme com sed :

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

Livre-se das novas linhas usando backticks, acrescentar

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

Alimente a expressão resultante para bc

=> 24

Teste

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

1

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

3

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

24

Experimente online! (usa expansão aritmética bash, em vez de bc , pois o último não está disponível)

zepelim
fonte
10

Caracóis , 19 bytes

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

Experimente online.

A idéia é que começamos em algum lugar na extremidade mais direita da rede e depois viajemos para algum lugar na parte inferior. O comprimento da aresta e a área da face são multiplicados pelo mecanismo de contagem de todos os caminhos correspondentes.

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
fonte
4

JavaScript (ES6), 67 91

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

Teste

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
fonte
3

Ruby, 44

Funciona de acordo com um princípio semelhante a outras respostas: encontre o primeiro +para encontrar a profundidade, encontre o próximo .depois +para encontrar a largura e conte o número |no final da linha e adicione 1 para encontrar a altura.

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

ungolfed no programa de teste

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.
Level River St
fonte
3

05AB1E , 21 bytes

Seja We Hseja, respectivamente, a largura e a altura da entrada - não a caixa. Em seguida, as dimensões da caixa A, Be Cseguir estas regras:

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

A figura a seguir mostra o que A, Be Csão, em termos de nomes de ponta:

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

Daí as fórmulas acima. Este programa calcula A, deduz os valores de Be Ce, finalmente, calcula o seu produto.

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

Experimente online!

Versão anterior - Abordagem diferente - 26 bytes

|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
fonte
2

Abaixo 93 , 56 bytes

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

Experimente Online!

Explicação:

O volume da caixa pode ser calculado multiplicando o número de .s na primeira linha antes de qualquer outro caractere, pelo número de +e -s na primeira linha - 1 e o número de linhas que começam com |+ 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

Eu tive que mover as linhas de IP para cima em vez de para baixo, a fim de usar a vertical se estiver na terceira linha. Se o IP estivesse descendo as linhas, a vertical se forçaria o topo da pilha a 1 ao atingir a seguinte horizontal se, enviando-a na direção errada.

MildlyMilquetoast
fonte
2

Haskell, 64 56 bytes

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

Experimente online!

Explicação

Espera-se que a entrada seja uma lista de cadeias para cada linha, portanto, no fparâmetro xestá a primeira linha e ruma lista das linhas restantes.

  1. fst(span(>'+')x)retorna o .prefixo-da primeira linha como uma string, assim length(fst(span(>'+')x))como a primeira dimensão d1.
  2. Uma compreensão de lista pode atuar como filtro, por exemplo, ['-' | '-' <- x]retorna uma sequência de tudo -na primeira linha, 1 + length['-' | '-' <- x]gerando a segunda dimensão d2.
  3. Analogamente, o número de |na primeira linha pode ser contado, assim 1 + length['|' | '|':_ <- r]como a terceira dimensão d3.

As compreensões de lista de 2. e 3. podem ser reduzidas para 1+sum[1|'-'<-x]e 1+sum[1|'|':_<-r]construindo uma lista de itens para cada ocorrência de '-' ou '|' e depois pegando a soma. Podemos colocar ainda mais o exterior 1+para a compreensão da lista anexando -ao xe "|"para rpara produzir sum[1|'-'<-'-':x]e sum[1|'|':_<-"|":r]. Agora podemos combinar as duas compreensões de lista colocando os dois predicados na mesma compreensão: sum[1|'|':_<-"|":r,'-'<-'-':x]Convenientemente, isso calcula exatamente o produto das duas dimensões, porque para listas Fe Ga seguinte compreensão de lista é o produto cartesiano F x G =[(a,b)|a<-F,b<-G].

Finalmente, em vez de multiplicar 1. pela combinação de 2. e 3., podemos usar o >>operador nas listas: F>>Grepete os G length Ftempos e concatena o resultado. Então fst(span(>'+')x)>>[1|'|':_<-"|":r,'-'<-'-':x]repete a lista de d2*d3uns d1tempos, produzindo uma lista de d1*d2*d3aqueles que são então somados até obter o volume.

Laikoni
fonte
Você pode considerar a entrada como uma lista de cadeias, removendo a necessidade lines.
Zgarb
@ Zgarb Obrigado, isso economiza alguns bytes.
Laikoni
1

Java 8, 185 129 bytes

graças ao Zgarb por -56 bytes

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

Explicação

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

onde ae bsão as dimensões da base e hé a altura. Você pode encontrar hcontando as primeiras hlinhas em que começa com a ..

Bobas_Pett
fonte
Você pode considerar a entrada como uma matriz ou seqüências de caracteres, portanto não há necessidade de dividi-la manualmente.
Zgarb
oops thx, fixando-o ...
Bobas_Pett
1

Java, 112 bytes

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

Expandido:

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
Andrey
fonte
1

Powershell, 68 67 bytes

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

Nota: "$args"|% i*f + é um atalho para"$args".indexOf('+')

Explicação

Boa explicação tirada da resposta do Osable :

Seja We Hseja, respectivamente, a largura e a altura da entrada - não a caixa. Em seguida, as dimensões da caixa A, Be Cseguir estas regras:

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

A figura a seguir mostra o que A, Be Csão, em termos de nomes de ponta:

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

E Cé a posição do primeiro +na primeira linha da entrada.

Script de teste:

$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"
}

Saída:

True: 1
True: 3
True: 12
True: 16
True: 16
True: 18
True: 24
True: 120
confuso
fonte
0

Wolfram Language (Mathematica) , 64 bytes

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

Experimente online!

Usa o número de ., |e \ncaracteres na entrada para resolver para o volume. Parece estúpido porque há uma nova linha real no lugar de \n.

Se A, Be Csão os lados, em seguida . = 2C(A+2C), | = 5B+4C-9e \n = B+2C, por isso, podemos resolver para o volume ABCem termos dessas três contagens de caracteres.

Misha Lavrov
fonte