ASCII 상자의 볼륨


40

소개

이 문제에서는 직사각형 입방체 (3D 상자) 의 그물 (펼친 표면)의 ASCII 표현을 입력으로 제공합니다 . 형식은 다음과 같습니다.

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

직육면체의 각면은- 문자로 #둘러싸인 사각형입니다 +-|. 그물의 외부는 .s 로 채워져 있습니다 . 그물은 항상 같은 방향을 갖습니다. 네 개의 인접한면으로 둘러싸인 가운데가 있고 가운데의 대응 부분은 입력의 오른쪽 경계에 있습니다. 입력은 .s로 직사각형 모양으로 채워 지며 s의 추가 행 또는 열을 포함하지 않습니다 ..

작업

당신의 임무는 위와 같이 다이어그램을 입력하고, 그것이 나타내는 직육면체의 부피, 즉 높이, 너비 및 깊이의 곱인 것을 계산하는 것입니다. 입력을 개행으로 구분 된 문자열 또는 문자열 배열로 사용할 수 있습니다.

각 모서리의 길이 +는 두 끝에서-문자 사이의 거리 입니다. 예를 들어 가로 가장자리의 +--+길이는 3이고 세로 가장자리의 길이는

+
|
|
|
+

모서리의 최소 길이는 1입니다. 위의 직육면체 예는 부피가 2 * 3 * 4 = 24입니다.

규칙과 득점

전체 프로그램이나 함수를 작성할 수 있으며 가장 낮은 바이트 수가 이깁니다.

테스트 사례

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

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

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

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

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

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

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

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

13
나는이 도전을 정말로 좋아한다. 입력이 너무 많은 중복 구조를 가지기 때문에 치수를 복구하는 방법에 대한 많은 선택이 있습니다.
xnor

답변:


25

망막 , 29 28 바이트

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

¶\|
$`
y

온라인으로 사용해보십시오!

있어 많은 나는이 확실하지 어떻게 최적 해요,하지만 이미 실제로 내가 생각했던 것보다 훨씬 짧은, 그래서 당신이 어떤면에 곱셈 할 지역에 따라 망막이 접근 할 수있는 방법,의는.

나는 현재 동일한 바이트 수로 두 가지 다른 솔루션을 가지고 있는데, 위의 접근법보다 약간 더 골프 타는 것 같습니다.

\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 의 수를 세는 것인데, 끝에 10 진수로 인쇄됩니다.


15

파이썬 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

배쉬 + coreutils, 83, 77 바이트

EDITS :

  • "Here String"을 사용하고 정규 표현식을 조금 최적화하여 6 바이트를 절약했습니다.

골프

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

4

자바 스크립트 (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

다른 답변 유사한 원리로 작동합니다 : 첫 번째 발견 +, 깊이를 찾을 다음 찾을 .애프터 +폭을 찾을 수를, 그리고 수를 계산 |라인의 끝에와 높이를 찾는 일을 추가 할 수 있습니다.

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

테스트 프로그램에서 ungolfed

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 바이트

하자 WH각각 폭과 입력의 높이 일 -하지 상자. 그런 다음 상자 크기 A를 지정 B하고 C다음 규칙을 따릅니다.

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

무엇 다음 그림 쇼 A, BC에지 이름의 측면에서입니다 :

....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_^#

온라인으로 사용해보십시오!

설명:

상자의 부피의 수 곱한 수 .의 수에 의해, 다른 문자 전에 첫 번째 라인들 +-(1), 및 시작 행의 수 - 제 라인 S |+ 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를 줄 대신 아래로 이동해야했습니다. IP가 다운 라인이 된 경우 수직 인 경우 스택의 상단을 1로 설정하면 다음 수평을 맞출 때 잘못된 방향으로 보냅니다.


2

하스켈, 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]리스트 FG대해 다음리스트 이해가 Cartesian product 이므로 두 차원의 곱을 정확하게 계산하는 것이 편리합니다 F x G =[(a,b)|a<-F,b<-G].

마지막으로 1과 2와 3의 조합을 곱하는 대신 >>연산자를 목록에서 사용할 수 있습니다. 시간을 F>>G반복 G length F하고 결과를 연결합니다. 그래서 fst(span(>'+')x)>>[1|'|':_<-"|":r,'-'<-'-':x]목록 반복 d2*d3것들 d1의 목록 산출 번 d1*d2*d3다음 볼륨을 얻기 위해 합산 것들.


입력을 문자열 목록으로 가져갈 필요가 없습니다 lines.
Zgarb

@ Zgarb 감사합니다, 이것은 약간의 바이트를 절약합니다.
Laikoni

1

Java 8, 185 129 바이트

-56 바이트의 Zgarb 덕분에

골프 :

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줄 을 세면 찾을 수 있습니다 ..


입력을 배열 또는 문자열로 취할 수 있으므로 수동으로 분리 할 필요가 없습니다.
Zgarb

죄송합니다 thx, 그것을
고쳐

1

자바, 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

파워 쉘, 68 67 바이트

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

참고 : "$args"|% i*f + 바로 가기됩니다 에 대한"$args".indexOf('+')

설명

Osable의 답변 에서 좋은 설명을 얻었습니다 .

하자 WH각각 폭과 입력의 높이 일 -하지 상자. 그런 다음 상자 크기 A를 지정 B하고 C다음 규칙을 따릅니다.

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

무엇 다음 그림 쇼 A, BC에지 이름의 측면에서입니다 :

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

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세 가지 문자 카운트의 관점있다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.