Draw an ASCII cuboid

Given three integers >= 2, create an ASCII cube in an orthogonal (cabinet) projection. The three integers represent height, width and depth (measured in visible characters) including the corners. The corners should be 'o's or '+', free choice.

w: 10, h: 5, d: 4 Thus gives:

   o--------o
/        /|
/        / |
o--------o  |
|        |  o
|        | /
|        |/
o--------o


Now, to make this slightly harder, all faces can either be solid, transparent or missing. We order the faces like this:

   o--------o
/        /|
/    2   / |
o--------o 3|
|        |  o
|   1    | /
|        |/
o--------o

---
|2|
-------
|5|1|3|
-------
|4|
---
|6|
---


And supply a list of tokens, S, T or M. The original example is thus:

w 10
h 5
d 4
S S S S S S

o--------o
/        /|
/        / |
o--------o  |
|        |  o
|        | /
|        |/
o--------o


If one face is transparent, we can see anything that is behind it:

T S S S S S

o--------o
/        /|
/        / |
o--------o  |
|  o-----|  o
| /      | /
|/       |/
o--------o

T T T T T T

o--------o
/|       /|
/ |      / |
o--------o  |
|  o-----|--o
| /      | /
|/       |/
o--------o


For pairs of missing faces, adjacent edges or corners are no longer visible:

M M S S S S

o--------o
/|       /|
/ |      / |
o  |     o  |
|  o-----|  o
| /      | /
|/       |/
o--------o

M M S S M S

o--------o
|       /|
|      / |
|     o  |
o-----|  o
/      | /
/       |/
o--------o


Code golf, shortest code wins! Trailing spaces and newlines are fine, you're free to choose input method and input order.

• How strict is your input format? can I make a function with 9 parameters? Jun 15, 2017 at 14:36
• @LiefdeWen you're free to choose input method and input order. And as nothing says otherwise, any of the default input/output methods can be used. Jun 15, 2017 at 15:10
• Can I take an integer as bitmap for the transparent/solid flags? Jun 20, 2017 at 5:45
• @Titus Well.. alright. I guess it's a bit more entertaining if you actually can test the values by your self. Jun 22, 2017 at 14:15

Charcoal, 190 181 bytes

ＮωＡ⁻ω²ςＮηＡ⁻η²γＮδＡ⁻δ²χＡ⪪Ｓ αＦ›⊟αMＦ⟦ςγςγ⟧«oκ↶»Ｆ∧›⊟αM²«oς↷³oχ↷¹»Ｆ∧›⊟αM²«↷³oχ↷³oγ↶»Ｍ⁻ωδ⁻δηＦ⁼§α²SＧ↗δ↓η↙δ↑η Ｆ∧›⊟αM²«↶¹oχ↷³oγ↷»Ｆ⁼§α¹SＧ↗δ←ω↙δ→ω Ｆ∧›⊟αM²«↶¹oχ↶³oς»Ｆ⁼§α⁰SＵＯ±ωη ↷Ｆ›⊟αMＦ⟦γςγς⟧«oκ↷


Try it online! Link is to verbose version of code. Edit: Saved 9 bytes by optimising my conditions. Charcoal has no else token, so if commands always have two alternatives, unless they're at the end of a block or program. To avoid this, I use for (<bool>) instead of if (<bool>) which has a similar effect when the expression can only have the values 0 or 1 but saves a byte. (In order to achieve this I had to change the expressions so that they were always true when the body needed to be executed.) I was also able to optimise if (<bool>) for (<int>) into for (And(bool, int)).

• Holy Christ O_O. I couldn't even figure out how to draw the cube itself using charcoal. Can you put up an example to draw a simple cube on the github examples folder? One that's been optimized? I want to compare my like... 50 byte answer to what it should've been. Jun 16, 2017 at 21:09
• @carusocomputing Sorry, I'm unclear as to what you mean by "simple cube", and I'm not an author of Charcoal itself, so I can't add an example.
– Neil
Jun 16, 2017 at 21:26
• You aren't?! Holy crap, who is? I honestly thought you were. Also, I'd ask to be a charcoal contributor. You could easily become one on github :). You're talented in the language, obviously. And by "simple cube" I mean the first half of the challenge, just making an X * Y * Z ASCII cube. Jun 16, 2017 at 21:50
• @carusocomputing ASCII-only is the main contributor as far as I can tell, although the esolang wiki does credit a second contributor.
– Neil
Jun 16, 2017 at 21:51
• at the very least I'd contact them with a few of your examples, you've taken it further than anyone else I've seen. I'd love to get more explanations of your code, I've followed your Charcoal answers for a bit now because the language is interesting to me. Jun 16, 2017 at 21:53

JavaScript (ES6), 318314 308 bytes

Takes width, height and depth as integers and the faces as an array of characters.

(w,h,d,l,M=(n,F)=>[...Array(n+1).keys()].map(F),a=M((L=w--+d)*(h--+--d),i=>++i%L?' ':
),D=(t,Y=0,X=d,W=t&1?d:w,H=t&2?d:h,F=l[t>>2])=>F>'R'&&M(W,i=>M(H,j=>a[p=L*(Y+j-i*(t&1))+X+i-(t&2?j:0)]=(x=!(i&&i-W)|2*!(j&&j-H))?' |-o|/o/-o'[t%4*3+x]:a[F>'S'?p:0])))=>D(20)&D(D(14,h)&D(17,d,0),d,D(9,d,w)&D(6))||a.join


How?

The function M() processes a given callback F on a given range [0...n].

M = (n, F) => [...Array(n + 1).keys()].map(F)


The variable a holds a flat array representing a grid of size (w+d) x (h+d-1). It is initially filled with rows of spaces terminated with newlines.

a = M((L = w-- + d) * (h-- + --d), i => ++i % L ? ' ' : '\n')


The function D() is used to 'draw' a face of the cuboid.

The two least significant bits of the parameter t hold the face type:

• 0 = rear / front
• 1 = left / right
• 2 = bottom / top

Bits #2 to #4 hold the 0-based face index.

D = (                                           // given:
t, Y = 0, X = d,                              // - the type and the initial coordinates
W = t & 1 ? d : w,                            // - the drawing width
H = t & 2 ? d : h,                            // - the drawing height
F = l[t >> 2]                                 // - the character representing the status
) =>                                            //
F > 'R' &&                                    // provided that the face is not missing:
M(W, i =>                                     // for each i in [0...W]:
M(H, j =>                                   //  for each j in [0...H]:
a[                                        //    update the output
p = L * (Y + j - i * (t & 1)) +         //    at position p
X + i - (t & 2 ? j : 0)             //
] =                                       //    with either:
(x = !(i && i - W) | 2 * !(j && j - H)) ? //    - '|', '-' or '/' on edges
' |-o|/o/-o'[t % 4 * 3 + x]             //    - or 'o' on vertices
:                                         //
a[F > 'S' ? p : 0]                      //    - or a space on solid faces
)                                           //    - or the current character on
)                                             //      transparent faces


Faces are drawn in the following order:

D(5 * 4 + 0, 0, d)  // face #5 (rear)
D(3 * 4 + 2, h, d)  // face #3 (bottom)
D(4 * 4 + 1, d, 0)  // face #4 (left)
D(2 * 4 + 1, d, w)  // face #2 (right)
D(1 * 4 + 2, 0, d)  // face #1 (top)
D(0 * 4 + 0, d, 0)  // face #0 (front)


Demo

let f =

(w,h,d,l,M=(n,F)=>[...Array(n+1).keys()].map(F),a=M((L=w--+d)*(h--+--d),i=>++i%L?' ':
),D=(t,Y=0,X=d,W=t&1?d:w,H=t&2?d:h,F=l[t>>2])=>F>'R'&&M(W,i=>M(H,j=>a[p=L*(Y+j-i*(t&1))+X+i-(t&2?j:0)]=(x=!(i&&i-W)|2*!(j&&j-H))?' |-o|/o/-o'[t%4*3+x]:a[F>'S'?p:0])))=>D(20)&D(D(14,h)&D(17,d,0),d,D(9,d,w)&D(6))||a.join

let update = _ => O.innerHTML = f(W.value, H.value, D.value, [...F.value])
update()
<label>Width <input id="W" size="3" value="10" oninput="update()" /></label>
<label>Height <input id="H" size="3" value="5" oninput="update()" /></label>
<label>Depth <input id="D" size="3" value="4" oninput="update()" /></label>
<label>Faces <input id="F" size="6" value="MMSSMS" oninput="update()" /></label>
<pre id="O"></pre>

SOGL V0.11, 200194193192 190 bytes

b³@*⁶
ž}1}X⁵
;aκ⁴
2-³
* o1Ο²
d=?a³:?∫:¹
be.Aā6∫D,ζLI%:C?abe"DCa∫:c+H⁴d+ /ž}{"a+Hy"e³┐²čž|"b³┌²žz"EBAøp”,ōkB°s9θW=*↑(⅜⅞~υ=\⁰ōwūΧ►ΣΤP░¶Ο⁽◄Φ7⅟▲s#‘┌Θdwι+#¶ŗ!!6c=?6d=?2aI⁶e³∙ž}5¹b+⁴Ie³@∙⁵}4¹2+⁴⁶⁵


Takes input in the order

width
height
depth
down-face
left-face
back-face
top-face
right-face
front-face


Tied!
Try it Here! (compressed value changed to be V0.12 compatible)