Volume kotak ASCII

40

pengantar

Dalam tantangan ini, Anda diberikan input representasi ASCII dari jaring (permukaan tidak dilipat) berbentuk kubus persegi panjang (kotak 3D). Formatnya adalah ini:

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

Setiap wajah berbentuk kubus adalah persegi panjang #s dikelilingi oleh +-|karakter. Bagian luar jaring diisi dengan .s. Jaring akan selalu memiliki orientasi yang sama: ada wajah tengah yang dikelilingi oleh empat wajah tetangga, dan lawan dari wajah tengah berada di perbatasan kanan input. Input diisi dengan .s ke bentuk persegi panjang dan tidak akan berisi baris atau kolom ekstra .s.

Tugas

Tugas Anda adalah mengambil diagram input seperti di atas, dan menghitung volume berbentuk kubus yang diwakilinya, yang hanya merupakan produk dari tinggi, lebar, dan dalamnya. Anda dapat mengambil input sebagai string yang dibatasi-baris baru atau array string.

Panjang setiap tepi adalah jarak antara karakter- +di kedua ujungnya. Misalnya, tepi horizontal +--+memiliki panjang 3, dan tepi vertikal

+
|
|
|
+

memiliki panjang 4. Panjang minimum tepi adalah 1. Contoh berbentuk kubus di atas memiliki volume 2 * 3 * 4 = 24.

Aturan dan penilaian

Anda dapat menulis program atau fungsi lengkap, dan jumlah byte terendah menang.

Uji kasus

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

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

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

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

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

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

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

....+-----+..........
....|#####|..........
....|#####|..........
....|#####|..........
+---+-----+---+-----+
|###|#####|###|#####|
|###|#####|###|#####|
|###|#####|###|#####|
|###|#####|###|#####|
+---+-----+---+-----+
....|#####|..........
....|#####|..........
....|#####|..........
....+-----+..........
120
Zgarb
sumber
13
Saya sangat suka tantangan ini. Karena input memiliki struktur yang sangat berlebihan, ada banyak pilihan untuk memulihkan dimensi.
xnor

Jawaban:

25

Retina , 29 28 byte

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

¶\|
$`
y

Cobalah online!

Ada banyak cara untuk mendekati ini di Retina, tergantung pada area mana yang ingin Anda gandakan dengan sisi yang mana, jadi saya tidak yakin seberapa optimal ini, tetapi sebenarnya sudah jauh lebih pendek daripada yang saya kira.

Saat ini saya punya dua solusi lain pada jumlah byte yang sama yang tampaknya sedikit lebih golf daripada pendekatan di atas:

\G\..+¶

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

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

Meskipun dalam hal ini saya dapat menyimpan byte masing-masing jika saya berasumsi bahwa input diakhiri dengan linefeed baris tambahan, tetapi saya lebih suka tidak harus bergantung pada itu.

Dan satu lagi, masih pada 28 byte (yang ini sebenarnya mengalikan tiga sisi daripada mengalikan satu area dengan sisi):

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

Penjelasan

Gagasan utamanya adalah melipatgandakan area wajah di atas dengan panjang sisi vertikal yang menyentuh batas panjang input.

Saya akan menggunakan input berikut sebagai contoh (memiliki panjang sisi 2, 3 dan 4, jadi area 24):

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

Tahap 1: Transliterasi

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

Regex \G\..+¶cocok dengan garis yang dimulai dengan .dan berbatasan langsung dengan garis sebelumnya. Jadi ini cocok dengan semua garis yang berisi wajah paling atas. Panggung itu sendiri berubah .menjadi xdan semua karakter lain (salah satunya |+-#) menjadi y. Ini memberi kami hasil berikut:

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

Ini memiliki satu kolom lebih dari yang ykita butuhkan untuk mewakili area dari wajah atas. Kami memperbaikinya dengan tahap berikutnya.

Tahap 2: Ganti

xy

Jadi kami cocok dengan yyang didahului oleh x(yang persis satu dari mereka per baris) dan menghapus keduanya dari string. Kami mendapatkan ini:

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

Jadi sekarang kita punya area wajah atas yang diwakili oleh jumlah ys.

Tahap 3: Ganti

¶\|
$`

Tujuan kami di sini adalah untuk mengalikan area ini Adengan panjang sisi yang hilang, yaitu jumlah |pada awal garis ditambah 1. Namun, sebenarnya lebih mudah untuk mengalikannya dengan angka n+1karena kami sudah memiliki satu salinan dari Adalam string . Jika kami mengganti nbarang dengan A, kami berakhir dengan n+1salinan A. Ini membuat banyak hal lebih mudah bagi kita.

Jadi kami langsung mengganti apa pun |segera setelah umpan baris dengan semua yang ada di depan pertandingan. Ini membuat string cukup banyak dan membuatnya sedikit lebih besar dari yang kita butuhkan, tetapi jumlah ys akhirnya menjadi hasil yang kita cari:

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

Tahap 4: Cocokkan

y

Yang tersisa adalah menghitung angka ys, yang dicetak sebagai angka desimal di bagian akhir.

Martin Ender
sumber
15

Python 2, 57 byte

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

Fungsi yang mengambil daftar string.

Tentukan 3 dimensi secara terpisah:

l[0].find('+')
Indeks pertama +di baris pertama.

-~l[0].count('-')
Jumlah -tanda di baris pertama.

~`l`.count("'|")
Jumlah baris yang dimulai dengan |simbol, melalui representasi string dari daftar yang memiliki simbol kutipan sebelumnya.


62 byte:

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

Fungsi yang mengambil daftar string dan mencetak hasilnya.

Menemukan satu dimensi asebagai indeks +di baris pertama. Dua dimensi lain disimpulkan darinya dan lebar serta tinggi persegi panjang input.

Alternatif 63-byte, menemukan dimensi secara terpisah:

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

Bash + coreutils, 83, 77 byte

EDIT:

  • Disimpan 6 byte, dengan menggunakan "Here String" dan mengoptimalkan regexp sedikit

Golf

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

Dijelaskan

Transform dengan sed :

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

Singkirkan baris baru menggunakan backticks, tambahkan)

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

Umpan ekspresi yang dihasilkan ke bc

=> 24

Uji

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

1

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

3

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

24

Cobalah online! (menggunakan ekspansi aritmatika bash, alih-alih bc , karena yang terakhir tidak tersedia)

zeppelin
sumber
10

Siput , 19 byte

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

Cobalah online.

Idenya adalah bahwa kita mulai di suatu tempat di tepi paling kanan di internet, dan kemudian melakukan perjalanan ke suatu tempat di wajah paling bawah. Panjang tepi dan luas wajah dikalikan dengan mekanisme penghitungan semua jalur yang cocok.

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

JavaScript (ES6), 67 91

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

Uji

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

Ruby, 44

Bekerja pada prinsip yang mirip dengan jawaban lain: temukan yang pertama +untuk menemukan kedalaman, cari berikutnya .setelah +untuk menemukan lebar, dan hitung jumlah |pada akhir baris dan tambahkan 1 untuk menemukan ketinggian.

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

ungolfed dalam program tes

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

05AB1E , 21 byte

Biarkan Wdan Hmenjadi masing-masing lebar dan tinggi input - bukan kotak. Kemudian, dimensi kotak A, Bdan Cikuti aturan ini:

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

Gambar berikut menunjukkan apa A, Bdan Capa, dalam hal nama tepi:

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

Karena itulah rumus di atas. Program Toedjoe menghitung ini A, menyimpulkan nilai-nilai Bdan Cdan akhirnya menghitung produk mereka.

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

Cobalah online!

Versi sebelumnya - Pendekatan berbeda - 26 byte

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

Menembus 93 , 56 byte

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

Cobalah secara Online!

Penjelasan:

Volume kotak dapat dihitung dengan mengalikan jumlah .s pada baris pertama sebelum karakter lain, dengan jumlah +dan -s pada baris pertama - 1, dan jumlah baris yang dimulai dengan |+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

Saya harus memindahkan garis IP ke atas daripada ke bawah untuk menggunakan vertikal jika di baris ke-3. Jika IP akan turun garis, vertikal jika akan memaksa bagian atas tumpukan menjadi 1 ketika memukul horizontal berikut jika, mengirimnya ke arah yang salah.

MildlyMilquetoast
sumber
2

Haskell, 64 56 byte

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

Cobalah online!

Penjelasan

Input diharapkan menjadi daftar string untuk setiap baris, jadi dalam fparameternya xadalah baris pertama dan rdaftar baris yang tersisa.

  1. fst(span(>'+')x)mengembalikan .-prefix dari baris pertama sebagai string, begitu length(fst(span(>'+')x))juga dimensi pertama d1.
  2. Pemahaman daftar dapat bertindak sebagai filter, misalnya ['-' | '-' <- x]mengembalikan string semua -di baris pertama, sehingga 1 + length['-' | '-' <- x]menghasilkan dimensi kedua d2.
  3. Secara analog jumlah |di baris pertama dapat dihitung, demikian 1 + length['|' | '|':_ <- r]juga dimensi ketiga d3.

Pemahaman daftar 2. dan 3. dapat disingkat menjadi 1+sum[1|'-'<-x]dan 1+sum[1|'|':_<-r]dengan membangun daftar yang untuk setiap kemunculan '-' atau '|' dan kemudian mengambil jumlahnya. Kami lebih lanjut dapat menempatkan luar 1+ke dalam daftar pemahaman dengan menambahkan -untuk xdan "|"untuk rmenghasilkan sum[1|'-'<-'-':x]dan sum[1|'|':_<-"|":r]. Sekarang kita dapat menggabungkan kedua daftar pemahaman dengan menempatkan kedua predikat dalam pemahaman yang sama: sum[1|'|':_<-"|":r,'-'<-'-':x]Mudah ini menghitung persis produk dari dua dimensi karena untuk daftar Fdan Gpemahaman daftar berikut adalah produk Cartesius F x G =[(a,b)|a<-F,b<-G].

Akhirnya, alih-alih mengalikan 1. dengan kombinasi 2. dan 3. kita dapat menggunakan >>operator pada daftar: F>>Gmengulangi G length Fkali dan menyatukan hasilnya. Jadi fst(span(>'+')x)>>[1|'|':_<-"|":r,'-'<-'-':x]ulangi daftar d2*d3yang d1kali, menghasilkan daftar d1*d2*d3yang kemudian diringkas untuk mendapatkan volume.

Laikoni
sumber
Anda dapat mengambil input sebagai daftar string, menghilangkan kebutuhan lines.
Zgarb
@ Zgarb Terima kasih, ini menghemat beberapa byte.
Laikoni
1

Java 8, 185 129 byte

terima kasih kepada Zgarb untuk -56 byte

golf:

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

Penjelasan

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

di mana adan badalah dimensi dari pangkalan dan htinggi. Anda dapat menemukan hdengan menghitung hbaris pertama di mana Anda mulai dengan a ..

Bobas_Pett
sumber
Anda dapat mengambil input sebagai array atau string, jadi tidak perlu membelahnya secara manual.
Zgarb
oops thx, memperbaikinya ...
Bobas_Pett
1

Java, 112 byte

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

Diperluas:

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
sumber
1

Powershell, 68 67 byte

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

Catatan: "$args"|% i*f + adalah jalan pintas untuk"$args".indexOf('+')

Penjelasan

Penjelasan yang bagus diambil dari jawaban Osable :

Biarkan Wdan Hmenjadi masing-masing lebar dan tinggi input - bukan kotak. Kemudian, dimensi kotak A, Bdan Cikuti aturan ini:

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

Gambar berikut menunjukkan apa A, Bdan Capa, dalam hal nama tepi:

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

Dan Cadalah posisi pertama +di baris pertama input.

Skrip uji:

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

Keluaran:

True: 1
True: 3
True: 12
True: 16
True: 16
True: 18
True: 24
True: 120
mazzy
sumber
0

Bahasa Wolfram (Mathematica) , 64 byte

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

Cobalah online!

Menggunakan jumlah ., |dan \nkarakter dalam input untuk memecahkan volume. Itu terlihat bodoh karena ada baris baru yang sebenarnya di tempat \n.

Jika A,, Bdan Csisi-sisinya, maka . = 2C(A+2C),, | = 5B+4C-9dan \n = B+2C, jadi kita dapat menyelesaikan volume ABCdalam hal ketiga karakter ini.

Misha Lavrov
sumber