Objętości skrzynek ASCII

40

Wprowadzenie

W tym wyzwaniu otrzymujesz jako dane wejściowe reprezentację ASCII siatki (rozłożonej powierzchni) prostokątnego prostopadłościanu (ramka 3D). Format jest następujący:

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

Każda twarz prostopadłościanu jest prostokątem #s otoczonym +-|-znakami. Zewnętrzna część siatki jest wypełniona .s. Sieć zawsze będzie miała tę samą orientację: środkowa ściana otoczona jest czterema sąsiadującymi ścianami, a odpowiednik środkowej ściany znajduje się po prawej stronie wejścia. Dane wejściowe są wypełnione .s do kształtu prostokąta i nie będą zawierać dodatkowych wierszy ani kolumn .s.

Zadanie

Twoim zadaniem jest wziąć jako dane wejściowe diagram jak wyżej i obliczyć objętość prostopadłościanu, który reprezentuje, który jest tylko iloczynem jego wysokości, szerokości i głębokości. Możesz wziąć dane wejściowe jako ciąg rozdzielany znakiem nowej linii lub tablicę ciągów.

Długość każdej krawędzi to odległość między +znakami na dwóch końcach. Na przykład krawędź pozioma +--+ma długość 3, a krawędź pionowa

+
|
|
|
+

ma długość 4. Minimalna długość krawędzi wynosi 1. Przykładowy prostopadłościan powyżej ma objętość 2 * 3 * 4 = 24.

Zasady i punktacja

Możesz napisać pełny program lub funkcję, a wygrywa najniższa liczba bajtów.

Przypadki testowe

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

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

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

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

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

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

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

....+-----+..........
....|#####|..........
....|#####|..........
....|#####|..........
+---+-----+---+-----+
|###|#####|###|#####|
|###|#####|###|#####|
|###|#####|###|#####|
|###|#####|###|#####|
+---+-----+---+-----+
....|#####|..........
....|#####|..........
....|#####|..........
....+-----+..........
120
Zgarb
źródło
13
Naprawdę podoba mi się to wyzwanie. Ponieważ dane wejściowe mają tak zbędną strukturę, istnieje wiele możliwości odzyskania wymiarów.
xnor

Odpowiedzi:

25

Retina , 29 28 bajtów

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

¶\|
$`
y

Wypróbuj online!

Istnieje wiele sposobów podejścia do tego w Retinie, w zależności od tego, który obszar chcesz pomnożyć przez którą stronę, więc nie jestem pewien, jak optymalne jest to, ale w rzeczywistości jest już znacznie krótsze, niż się spodziewałem.

Obecnie mam dwa inne rozwiązania o tej samej liczbie bajtów, które wydają się nieco bardziej grywalne niż powyższe podejście:

\G\..+¶

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

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

Chociaż w każdym z nich mogę zapisać bajt, jeśli założę, że dane wejściowe kończą się końcowym podawaniem linii, ale wolałbym nie polegać na tym.

I jeszcze jeden, wciąż o 28 bajtach (ten w rzeczywistości mnoży trzy strony zamiast mnożenia jednego obszaru przez bok):

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

Wyjaśnienie

Główną ideą jest pomnożenie obszaru twarzy na górze przez długość pionowej strony, która dotyka granicy długości wejścia.

Jako przykład wykorzystam następujące dane wejściowe (ma długości boków 2, 3 i 4, czyli obszar 24):

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

Etap 1: Transliteracja

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

Wyrażenie regularne \G\..+¶dopasowuje linię rozpoczynającą się od .i bezpośrednio przylegającą do poprzedniej linii. To pasuje do wszystkich linii zawierających górną ścianę. Sama scena zamienia się .w xi wszystkie inne postacie (dowolne |+-#) w y. To daje nam następujący wynik:

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

Ma jeszcze jedną kolumnę, yniż potrzebujemy, aby przedstawić obszar górnej powierzchni. Naprawiamy to w następnym etapie.

Etap 2: Wymień

xy

Dopasowujemy więc ypoprzednik x(który jest dokładnie jednym z nich w wierszu) i usuwamy je oba z ciągu. Otrzymujemy to:

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

Mamy teraz obszar górnej powierzchni reprezentowany przez liczbę ys.

Etap 3: Wymień

¶\|
$`

Naszym celem jest pomnożenie tego obszaru Aprzez brakującą długość boku, czyli liczbę |na początku wiersza plus 1. Jednak w rzeczywistości łatwiej jest pomnożyć przez liczbę, n+1ponieważ mamy już jedną kopię Aciągu . Jeśli zastąpimy nrzeczy A, otrzymamy n+1kopie A. To nam znacznie ułatwia.

Więc po prostu zastępujemy dowolne |bezpośrednio po wysunięciu linii wszystkim przed meczem. Spowoduje to, że struna dość mocno i sprawia, że ​​jest ona nieco większa niż potrzebujemy, ale liczba ys kończy się wynikiem, którego szukamy:

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

Etap 4: Mecz

y

Pozostało tylko policzyć liczbę ys, która jest drukowana jako liczba dziesiętna na końcu.

Martin Ender
źródło
15

Python 2, 57 bajtów

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

Funkcja, która przyjmuje listę ciągów.

Określa 3 wymiary osobno:

l[0].find('+')
Indeks pierwszego +w pierwszym rzędzie.

-~l[0].count('-')
Liczba -znaków w pierwszym rzędzie.

~`l`.count("'|")
Liczba wierszy rozpoczynających się od |symbolu, poprzez ciąg znaków reprezentujący listę z symbolem cytatu przed nią.


62 bajty:

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

Funkcja, która pobiera listę ciągów i wypisuje wynik.

Znajduje jeden wymiar ajako indeks +w pierwszym wierszu. Pozostałe dwa wymiary są z niego wywnioskowane oraz szerokość i wysokość prostokąta wejściowego.

63-bajtowa alternatywa polegająca na oddzielnym określaniu wymiarów:

lambda l:l[0].find('+')*~l[0].count('-')*~zip(*l)[0].count('|')
xnor
źródło
11

Bash + coreutils, 83, 77 bajtów

EDYCJE:

  • Zapisano 6 bajtów, używając „Here String” i nieco optymalizując wyrażenie regularne

Grał w golfa

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

Wyjaśniono

Przekształć za pomocą sed :

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

Pozbądź się nowych linii, używając backticków, dołącz)

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

Wprowadź wynikowe wyrażenie do bc

=> 24

Test

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

1

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

3

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

24

Wypróbuj online! (używa rozszerzenia arytmetycznego bash zamiast bc , ponieważ ten ostatni nie jest dostępny)

zepelin
źródło
10

Ślimaki , 19 bajtów

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

Wypróbuj online.

Chodzi o to, że zaczynamy gdzieś na skraju prawej krawędzi w sieci, a następnie udajemy się gdzieś w dolną ścianę. Długość krawędzi i powierzchnia twarzy są mnożone przez mechanizm zliczania wszystkich pasujących ścieżek.

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
źródło
4

JavaScript (ES6), 67 91

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

Test

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
źródło
3

Ruby, 44

Działa na zasadzie podobnej do innych odpowiedzi: znajdź pierwszą, +aby znaleźć głębokość, znajdź następną .po, +aby znaleźć szerokość i policz liczbę |na końcu linii i dodaj 1, aby znaleźć wysokość.

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

nie wziął udziału w programie testowym

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
źródło
3

05AB1E , 21 bajtów

Niech Wi Hbędzie odpowiednio szerokością i wysokością danych wejściowych - nie pudełkiem. Następnie, wymiary skrzyni A, Ba Cwedług poniższych zasad:

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

Poniższy rysunek pokazuje co A, Bi Csą, w zakresie nazw brzegowych:

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

Stąd powyższe formuły. Ten program Oblicza A, dedukuje wartości Bi Cwreszcie oblicza swój produkt.

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

Wypróbuj online!

Poprzednia wersja - Inne podejście - 26 bajtów

|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
źródło
2

Befunge 93 , 56 bajtów

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

Wypróbuj online!

Wyjaśnienie:

Objętość pudełka można obliczyć mnożąc liczbę .sekund na pierwszej linii przed wszelkimi innymi postaciami, przez liczbę +i -s na pierwszej linii - 1, oraz liczbę wierszy, które zaczynają się od |+ 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

Musiałem przesunąć IP w górę, zamiast w dół, aby użyć pionu, jeśli w 3. linii. Jeśli adres IP spadał w dół, pionowe if zmusiłoby górę stosu do 1, gdy trafi w następujący poziomo if, wysyłając go w złym kierunku.

Łagodnie Milquetoast
źródło
2

Haskell, 64 56 bajtów

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

Wypróbuj online!

Wyjaśnienie

Dane wejściowe powinny być listą ciągów dla każdej linii, więc w fparametrze xjest pierwszy wiersz i rlista pozostałych wierszy.

  1. fst(span(>'+')x)zwraca .prefiks pierwszej linii jako ciąg znaków, podobnie length(fst(span(>'+')x))jak pierwszy wymiar d1.
  2. Zrozumienie listy może działać jak filtr, np. ['-' | '-' <- x]Zwraca ciąg wszystkiego -w pierwszym wierszu, a więc 1 + length['-' | '-' <- x]zwraca drugi wymiar d2.
  3. Analogicznie |można policzyć liczbę w pierwszym rzędzie, podobnie 1 + length['|' | '|':_ <- r]jak trzeci wymiar d3.

Zrozumienie listy w punktach 2. i 3. można skrócić do 1+sum[1|'-'<-x]i 1+sum[1|'|':_<-r]budując listę takich dla każdego wystąpienia „-” lub „|” a następnie biorąc sumę. Możemy dodatkowo umieścić zewnętrznej 1+do listy pojmowania przez dołączenie -do xi "|"do rotrzymując sum[1|'-'<-'-':x]a sum[1|'|':_<-"|":r]. Teraz możemy połączyć oba zestawienia listowe, umieszczając oba predykaty w tym samym rozumieniu: sum[1|'|':_<-"|":r,'-'<-'-':x]Dogodnie oblicza to dokładnie iloczyn dwóch wymiarów, ponieważ dla list Fi Gponiższym zestawieniem list jest produkt kartezjański F x G =[(a,b)|a<-F,b<-G].

Wreszcie, zamiast mnożenia 1. przez kombinację 2. i 3. możemy skorzystać z >>operatora na listach: F>>Gpowtarza G length Fczasy i łączy wynik. fst(span(>'+')x)>>[1|'|':_<-"|":r,'-'<-'-':x]Powtarza więc listę d2*d3tych d1czasów, dając listę d1*d2*d3tych, które są następnie sumowane w celu uzyskania objętości.

Laikoni
źródło
Możesz wziąć dane wejściowe jako listę ciągów, eliminując potrzebę lines.
Zgarb
@Zgarb Dzięki, to oszczędza niektóre bajty.
Laikoni,
1

Java 8, 185 129 bajtów

dzięki Zgarbowi za -56 bajtów

grał w golfa:

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

bez golfa:

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

Wyjaśnienie

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

gdzie ai bsą wymiary podstawy i hjest wysokość. Możesz znaleźć h, licząc pierwsze hlinie, od których zaczynasz od ..

Bobas_Pett
źródło
Możesz wziąć dane wejściowe jako tablicę lub ciągi, więc nie musisz ręcznie ich dzielić.
Zgarb
Ups, dzięki, naprawiam ...
Bobas_Pett,
1

Java, 112 bajtów

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

Rozszerzony:

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
źródło
1

PowerShell, 68 67 bajtów

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

Uwaga: "$args"|% i*f + jest skrótem do"$args".indexOf('+')

Wyjaśnienie

Dobre wyjaśnienie pochodzi z odpowiedzi Osable :

Niech Wi Hbędzie odpowiednio szerokością i wysokością danych wejściowych - nie pudełkiem. Następnie, wymiary skrzyni A, Ba Cwedług poniższych zasad:

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

Poniższy rysunek pokazuje co A, Bi Csą, w zakresie nazw brzegowych:

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

I Cjest pozycją pierwszego +w pierwszym wierszu wejścia.

Skrypt testowy:

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

Wynik:

True: 1
True: 3
True: 12
True: 16
True: 16
True: 18
True: 24
True: 120
mazzy
źródło
0

Wolfram Language (Mathematica) , 64 bajty

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

Wypróbuj online!

Wykorzystuje szereg ., |i \nznaki na wejściu do rozwiązania dla objętości. Wygląda to głupio, ponieważ zamiast niego pojawiła się nowa linia \n.

Jeśli A, Bi Csą stronami, to . = 2C(A+2C), | = 5B+4C-9i \n = B+2C, więc możemy rozwiązać problem z objętością ABCpod względem tych trzech liczb znaków.

Misza Ławrow
źródło