[Question]
  [
This question is inspired by the cover of the book "Godel, Escher, Bach":
[![](https://i.stack.imgur.com/yg9UJ.jpg)](https://i.stack.imgur.com/yg9UJ.jpg)
The challenge here is to write a function that tells if three given letters can produce a 3D sculpture that can be read from three sides.
For this exercise, the only letters you can use are 26 5px \* 5px bitmaps:
![](https://s29.postimg.org/ohfm5uphz/letters.png)
Or in binary (A to Z):
```
01110  11110  01111  11110  11111  11111  11111  10001  11111  11111  10001  10000  10001  10001  01110  11110  01110  11110  01111  11111  10001  10001  10001  10001  10001  11111
10001  10001  10000  10001  10000  10000  10000  10001  00100  00100  10010  10000  11011  11001  10001  10001  10001  10001  10000  00100  10001  10001  10001  01010  01010  00010
10001  11110  10000  10001  11100  11110  10011  11111  00100  00100  11100  10000  10101  10101  10001  10001  10001  11111  01110  00100  10001  01010  10001  00100  00100  00100
11111  10001  10000  10001  10000  10000  10001  10001  00100  10100  10010  10000  10001  10011  10001  11110  10011  10010  00001  00100  10001  01010  10101  01010  00100  01000
10001  11110  01111  11110  11111  10000  11111  10001  11111  11100  10001  11111  10001  10001  01110  10000  01111  10001  11110  00100  01110  00100  01010  10001  00100  11111
```
The sculpture is formed by three letters in the following order:
* letter one on top,
* letter two on the left
* letter three on the right
* the bottom of letter one is bound to the top of the letter two.
Example:
![](https://s21.postimg.org/vz0htem4n/schema.png)
Your function may accept as input three uppercase letters (three chars or three strings of one letter), and output a boolean (true/false or 0/1) telling if the corresponding sculpture can exist.
Example:
```
f("B","E","G") // true  (because if you "sculpt out" B on top + E on the left + G on the right, and watch the three sides of the sculpture, you'll see exactly B, E and G as they are defined)
f("B","G","E") // false (because if you "sculpt out" B on top + G on the left + E on the right, and watch the three sides of the sculpture, you won't see a complete G and a complete E. Their shapes bother each other)
```
NB: you may return true even if the sculpture contains "flying pixels" (cubes or group of cubes that are attached to nothing).
Standard loopholes apply.
More precisely, you can't use external input besides the three letters, and you can't hardcode the 17576 possible answers in your source code
Shortest answer in characters in any language wins!
Have fun :)
  
[Answer]
# Mathematica 423
I added a section called "How blocking works".
## Ungolfed
(\*The binary data of the alphabet are stored as a single string in `s`. `vars` imports it and converts it into an array.) 
```
vars=IntegerDigits[#,10,5]&/@Transpose[ImportString[s,"Table"]];
get[char_]:=(ToCharacterCode[char]-64)[[1]];
cube=Flatten[Table[{i,j,k},{i,5},{j,5},{k,5}],2];
(* character slice along axis *)
slice[char_,layer_,axis_,bit_]:=Insert[(Reverse@#),layer,axis]&/@Position[Reverse@vars[[get[char]]],bit]
(* cuboid assembly  *)
charBlocks[{char_,axis_,bit_}]:=Flatten[Table[slice[char,k,axis,bit],{k,5}],1]
(* letters are those whose HOLES should be sculped out of the full cube *)
sculpturePoints[letters_(*{char_,axis_,bit_}*)]:=Complement[cube,Union[Join@@(charBlocks/@letters(*{char,axis,bit}*))]];
collapse[letters_(*{char_,axis_,bit_}*),axis_]:=Union[Reverse/@(Delete[#,axis]&/@sculpturePoints[letters(*{char,axis,bit}*)])](*/.{x_,y_}\[RuleDelayed] {6-x,y}*)
vQ[l_]:=collapse[l,3]==collapse[{l[[1]]},3]\[And]collapse[l,2]==collapse[{l[[2]]},2]\[And]collapse[l,1]==collapse[{l[[3]]},1]
validQ@l_:= vQ[{{l[[1]],3,0},{l[[2]],2,0},{l[[3]],1,0}}]
perspective[letts_,view_:1]:=
Graphics3D[{AbsolutePointSize[10],Cuboid/@sculpturePoints[letts]},
ImageSize-> 120,
ViewPoint-> Switch[view,1,{0,0,\[Infinity]},2,{0,-\[Infinity],0},3,{\[Infinity],0,0},4,Top,5,Front,6,Right,True,{0,0,\[Infinity]}],
PlotLabel-> Switch[view,1,"top orthogonal view",2,"front orthogonal view",3,"right orthogonal view",4,"top close-up view",5,"front close-up view",6,"right close-up view"],
ImagePadding->10]
```
---
## Example
Is the cube `{"B", "G", "E"}` valid? (i.e. Will the three letters project correctly onto the walls?) 
```
validQ[{"B", "G", "E"}]
```
> 
> False
> 
> 
> 
**Illustrations**
The figures below show how BGE is rendered. The upper row of figures takes orthogonal perspectives, as if the viewer were positioned at infinite distances from the cube.
The lower row shows how the blocks would look from close up. The 3D figures can be manually rotated to inspect precisely where the individual unit cubes are positioned.
A problem occurs with the letter "G". There is nothing connecting the serif to the rest of the letter.
```
pts = {{"B", 3, 0}, {"G", 2, 0}, {"E", 1, 0}}
GraphicsGrid@Partition[Table[perspective[pts, view], {view, 1, 6}], 3]
```
![bge](https://i.stack.imgur.com/DaMLd.png)
---
BEG, however, should work fine.
```
 validQ[{"B", "E", "G"}]
```
> 
> True
> 
> 
> 
```
pts2 = {{"B", 3, 0}, {"E", 2, 0}, {"G", 1, 0}}
GraphicsGrid@Partition[Table[perspective[pts2, view], {view, 1, 6}], 3]
```
![beg](https://i.stack.imgur.com/rbuCY.png)
---
## How Does Blocking Work?
Please excuse me if this seems obvious, but perhaps some folks will want to visualize how 
how letters interfere with each other, canceling their 3D pixels.
Let's follow what happens to the letter G, in the BGE cube rendering.
We'll be paying special attention to the [voxel](http://en.wikipedia.org/wiki/Voxel) (3D pixel or unit cube) below. That is the pixel that disappears in the BGE cube. It is the pixel corresponding to Row 4, Column 5 in the bit array and in the corresponding array plot.
![blocking 1](https://i.stack.imgur.com/OtHdw.png)
---
In the x y plane, the pixel corresponds to the gray disk at point (5,2). But because we're going to work in 3D, we need to consider the 5 positions in the *shaft* from (5,1,2) to (5,5,2). If any of those pixels survives sculpting by the letters B and E, we'll be able to see the pixel of interest in the 3D projection on the wall.
![blocking 2](https://i.stack.imgur.com/ydaNI.png)
---
Letters interfere when pixels are removed from the solid block. In the left, the black arrow represents the carving out of pixels, corresponding to the bit at the bottom right; it has the value 0 for the letter B. Carving out removes the pixel at (5,1,2), along with those directly above and below it. Four pixels remain to be accounted for. 
![blocking 3](https://i.stack.imgur.com/ME6sl.png)
But as the right pane shows, the letter E sculpts out the remaining pixels of interest, (5,2,2) (5,3,2), (5,4,2) and (5,5,2). (This is due to the fact that the letter E has bits equal to 0 in the fourth row, from column 2 through column 5.) As a result, not a single pixel remains among those that were needed to ensure shade at point (5,2) on the far wall (for the letter G). Instead, there will be a bright spot corresponding to a hole in the letter G! The cube BGE is no good because it incorrectly renders G.
## Golfed 423 chars
The function `h` served the same role as `validQ` in the unGolfed code.
The rendering function, `perspective`, is not included because it does not contribute to, and is not required by, the challenge.
```
x=Reverse;q=Flatten;
g@c_:=(ToCharacterCode[c]-64)[[1]];
r[{c_,a_,b_}]:=q[Table[Insert[(x@#),k,a]&/@Position[x@(IntegerDigits[#,10,5]&/@
Transpose[ImportString[s,"Table"]])[[g[c]]],b],{k,5}],1]
p@l_:=Complement[q[Table[{i,j,k},{i,5},{j,5},{k,5}],2],Union[Join@@(r/@l)]];
w[l_,a_]:=Union[x/@(Delete[#,a]&/@p[l])]
v@l_:=w[l,3]==w[{l[[1]]},3]\[And]w[l,2]==w[{l[[2]]},2]\[And]w[l,1]==w[{l[[3]]},1]
h@l_:= v[{{l[[1]],3,0},{l[[2]],2,0},{l[[3]],1,0}}]
```
[Answer]
# Prolog, ~~440~~, 414
```
:- encoding(utf8).
i(I) :- between(0,4,I).
h(T,L,R,X,Y,Z) :- i(X),i(Y),i(Z),I is 4-X,c(T,Z,I),c(L,Z,Y),c(R,X,Y).
f(T,L,R) :- forall((i(U),i(V),I is 4-V),((\+c(T,U,V);h(T,L,R,I,Y,U)),(\+c(L,U,V);h(T,L,R,X,V,U)),(\+c(R,U,V);h(T,L,R,U,V,Z)))).
c(C,X,Y) :- char_code(C,N),i(X),i(Y),Z is X+5*Y+25*(N-65),I is floor(Z/15),O is (Z mod 15),string_code(I,"䙎㹟䘑߯硁䙏縑ԁࠟя摟䠑䠑ᐑ粤Ⴟ䔅┉ё籁垑䙑曓䗱㩑䙏㡏晑䘞䕟㡞縐Ⴄ䙄㩑⩑䒪噑⩊䕤ᅱ粤ࢨ?",V),1 is (V-32)>>O/\1.
```
The program is called like this:
```
?- f('B','E','G').
true.
?- f('B','G','E').
false.
```
`Prolog` seemed to be a good choice, since it's easy to represent the problem in first order logic. Also `Prolog` provides potent functionality for solving this kind of problem.
**However, since the code is golfed, I guess I should add some explanation.**
### Mildly golfed version
```
:- encoding(utf8).
i(I) :- between(0,4,I).
t(C,X,Z) :- I is 4-X,c(C,Z,I).
l(C,Y,Z) :- c(C,Z,Y).
r(C,X,Y) :- c(C,X,Y).
h(T,L,R,X,Y,Z) :- i(X),i(Y),i(Z),t(T,X,Z),l(L,Y,Z),r(R,X,Y).
u(T,L,R) :- forall((i(U),i(V),I is 4-V,c(T,U,V)),h(T,L,R,I,Y,U)).
v(T,L,R) :- forall((i(U),i(V),c(L,U,V)),h(T,L,R,X,V,U)).
w(T,L,R) :- forall((i(U),i(V),c(R,U,V)),h(T,L,R,U,V,Z)).
f(T,L,R) :- u(T,L,R),v(T,L,R),w(T,L,R).
c(C,X,Y) :- char_code(C,N),i(X),i(Y),Z is X+5*Y+25*(N-65),I is floor(Z/15),O is (Z mod 15),string_code(I,"䙎㹟䘑߯硁䙏縑ԁࠟя摟䠑䠑ᐑ粤Ⴟ䔅┉ё籁垑䙑曓䗱㩑䙏㡏晑䘞䕟㡞縐Ⴄ䙄㩑⩑䒪噑⩊䕤ᅱ粤ࢨ?",V),1 is (V-32)>>O/\1.
```
The coordinates corresponding to the pixels on each side of the dice can be easily converted to a 3D coordinate system. I use `T`,`L` and `R` for top(1), left(2) and right(3) side. `u` and `v` are used for the coordinates in the images:
* **T**: `(u,v) -> (4-v, ?, u)`
* **L**: `(u,v) -> (?, v, u)`
* **R**: `(u,v) -> (u, v, ?)`
The results for each active (i.e. black) pixel are combined to a set of "3D-pixels" that can be acitvated without changing the look of the object from this side. The intersection of the sets for each side are all 3D-pixels, that can be activated without adding pixels, that would obstruct the view (i.e. looking from at least one side there would be a pixel that shouldn't be there).
All that remains is to check for each side, if there is a pixel in the intersection that blocks the view, where it's necessary.
This leads to the predicates in the program:
* **f**: does the final check; takes the letters at the top, the left side and the right side
* **u**, **v** and **w**: do the checks, if for every pixel active on the side there is a 3D-pixel in the intersection, that blocks the view
* **h**: checks, for the existence of a pixel in the intersection
* **t**,**l**,**r**: checks, if a 3D-pixel can be blocked from top, left and right side.
* **c**: checks for the pixel in the image of a letter. The string in there may look a bit strange, but it's only a compact way to store the image data. It's simply a character sequence with the following values(hex notation):
```
[464e,3e5f,4611,7ef,7841,464f,7e11,501,81f,44f,645f,4811,4811,1411,7ca4,10bf,4505,2509,451,7c41,5791,4651,66d3,45f1,3a51,464f,384f,6651,461e,455f,385e,7e10,10a4,4644,3a51,2a51,44aa,5651,2a4a,4564,1171,7ca4,8a8,3f]
```
Each of these characters stores the data for 3 pixel rows in letter image(s) (=15 pixel). The pixels are also reordered so that the data is stored at one location and not divided across multiple rows, like the data of the OP.
## Mathematic formulation
![formula](https://chart.googleapis.com/chart?cht=tx&chl=I%3D%5C%7Bn%20%5Cin%20%5Cmathbb%7BN%7D%20%7C%200%20%5Cleq%20n%20%5Cleq%204%20%5C%7D)
### Input data
![formula](https://chart.googleapis.com/chart?cht=tx&chl=C_%5Cbeta%20%3D%20%5C%7B(u%2Cv)%20%7C%20%5Ctext%7Bpixel%20at%20position%20%7D%20(u%2Cv)%20%5Ctext%7B%20is%20black%20in%20image%20for%20char%20%7D%5Cbeta%5C%7D)
### Conversion from pixel in one char to set of 3D-pixels that obstruct the view for this pixel
![formula](https://chart.googleapis.com/chart?cht=tx&chl=T((u%2Cv))%20%3D%20%5C%7B(x%2Cy%2Cz)%20%5Cin%20I%5E3%20%7C%20x%3D4-v%20%5Cwedge%20u%3Dz)%5C%7D)
![formula](https://chart.googleapis.com/chart?cht=tx&chl=L((u%2Cv))%20%3D%20%5C%7B(x%2Cy%2Cz)%20%5Cin%20I%5E3%20%7C%20y%3Dv%20%5Cwedge%20u%3Dz)%5C%7D)
![formula](https://chart.googleapis.com/chart?cht=tx&chl=R((u%2Cv))%20%3D%20%5C%7B(x%2Cy%2Cz)%20%5Cin%20I%5E3%20%7Cx%3Du%20%5Cwedge%20y%3Dv)%5C%7D)
### Pixels that can be added safely(without obstructing the view in the wrong place)
![formula](https://chart.googleapis.com/chart?cht=tx&chl=H(%5Calpha%2C%5Cbeta%2C%5Cgamma)%3D%5C%7Bp%5Cin%20I%5E3%7Cp_s%5Cin%20C_%5Calpha%5Cwedge%20p%5Cin%20T(p_s)%5C%7D%5Ccap%5C%7Bp%5Cin%20I%5E3%7Cp_s%5Cin%20C_%5Cbeta%5Cwedge%20p%5Cin%20L(p_s)%5C%7D%5Ccap%5C%7Bp%5Cin%20I%5E3%7Cp_s%5Cin%20C_%5Cgamma%5Cwedge%20p%5Cin%20R(p_s)%5C%7D)
### Checks for each side, that the pixels that need to be obstructed can be obstructed safely
![formula](https://chart.googleapis.com/chart?cht=tx&chl=u(%5Calpha%2C%5Cbeta%2C%5Cgamma)%3D%5Cforall%20p%5Cin%20I%5E2%5C%3B%5C%3B%5Cexists%20p%27%20%5Cin%20H(%5Calpha%2C%5Cbeta%2C%5Cgamma)%5C%3B%5C%3B%3A(p%5Cin%20C_%5Calpha%5Crightarrow%20p%27%5Cin%20T(p)))
![formula](https://chart.googleapis.com/chart?cht=tx&chl=v(%5Calpha%2C%5Cbeta%2C%5Cgamma)%3D%5Cforall%20p%5Cin%20I%5E2%5C%3B%5C%3B%5Cexists%20p%27%20%5Cin%20H(%5Calpha%2C%5Cbeta%2C%5Cgamma)%5C%3B%5C%3B%3A(p%5Cin%20C_%5Cbeta%5Crightarrow%20p%27%5Cin%20L(p)))
![formula](https://chart.googleapis.com/chart?cht=tx&chl=w(%5Calpha%2C%5Cbeta%2C%5Cgamma)%3D%5Cforall%20p%5Cin%20I%5E2%5C%3B%5C%3B%5Cexists%20p%27%20%5Cin%20H(%5Calpha%2C%5Cbeta%2C%5Cgamma)%5C%3B%5C%3B%3A(p%5Cin%20C_%5Cgamma%5Crightarrow%20p%27%5Cin%20R(p)))
### Combinatin of checks for each side
![formula](https://chart.googleapis.com/chart?cht=tx&chl=f(%5Calpha%2C%5Cbeta%2C%5Cgamma)%3Du(%5Calpha%2C%5Cbeta%2C%5Cgamma)%5Cwedge%20v(%5Calpha%2C%5Cbeta%2C%5Cgamma)%5Cwedge%20w(%5Calpha%2C%5Cbeta%2C%5Cgamma))
[Answer]
# J - ~~223~~ ~~197~~ 191 char
A function taking a three char list as argument.
```
(_5#:\".'1b',"#:'fiiifalllvhhhheehhhvhhllvgkkkvnlhhvv444vhhvhhggvhjha44v1111vv848vv248vehhheciiivfjhhedmkkvilll9ggvggu111uo616ou121uha4ahg878ghpljh')((-:0<+/"1,+/"2,:+/)*`(*"1/)/)@:{~_65+3&u:
```
This golf relies heavily on a powerful feature of J called *rank*, which gives us the "sculpt out" and "watch side of" operations almost for free. To oversimplify it a bit, rank refers to the dimensionality of a noun or of a verb's natural arguments.
J has multidimensional arrays, and it is obvious that, say, a 3D array can be interpreted as a single 3D array, or as a list of matrices, or a 2D array of vectors, or a 3D array of scalars. So every operation in J can have its application controlled w.r.t. how to be spread over the argument. Rank 0 means apply on the scalars, rank 1 means apply on the vectors, and so on.
```
   1 + 2 + 3 + 4  NB. add these things together
10
   +/ 1 2 3 4     NB. sum the list by adding its items together
10
   i. 3 4         NB. 2D array, with shape 3-by-4
0 1  2  3
4 5  6  7
8 9 10 11
   +/"2 i. 3 4    NB. add the items of the matrix together
12 15 18 21
   0 1 2 3 + 4 5 6 7 + 8 9 10 11    NB. equivalent
12 15 18 21
   +/"1 i. 3 4    NB. now sum each vector!
6 22 38
   +/"0 i. 3 4    NB. now sum each scalar!
0 1  2  3
4 5  6  7
8 9 10 11
```
This becomes very powerful when you introduce dyadic (two-argument) functions, because if the shapes of the two arguments (after accounting for rank) are agreeable, J will do some implicit looping:
```
   10 + 1             NB. scalar addition
11
   10 20 30 + 4 5 6   NB. vector addition, pointwise
14 25 36
   10 + 4 5 6         NB. looping! 
14 15 16
   10 20 + 4 5 6      NB. shapes do not agree...
|length error
|   10 20    +4 5 6
```
When all your shapes are agreeable and you can specify the rank yourself, there are many ways to combine arguments. Here we show off some of the ways that you can multiply a 2D matrix and a 3D array.
```
   n =: i. 5 5
   n
 0  1  2  3  4
 5  6  7  8  9
10 11 12 13 14
15 16 17 18 19
20 21 22 23 24
   <"2 n *"2 (5 5 5 $ 1)  NB. multiply by 2-cells
+--------------+--------------+--------------+--------------+--------------+
| 0  1  2  3  4| 0  1  2  3  4| 0  1  2  3  4| 0  1  2  3  4| 0  1  2  3  4|
| 5  6  7  8  9| 5  6  7  8  9| 5  6  7  8  9| 5  6  7  8  9| 5  6  7  8  9|
|10 11 12 13 14|10 11 12 13 14|10 11 12 13 14|10 11 12 13 14|10 11 12 13 14|
|15 16 17 18 19|15 16 17 18 19|15 16 17 18 19|15 16 17 18 19|15 16 17 18 19|
|20 21 22 23 24|20 21 22 23 24|20 21 22 23 24|20 21 22 23 24|20 21 22 23 24|
+--------------+--------------+--------------+--------------+--------------+
   <"2 n *"1 (5 5 5 $ 1)  NB. multiply by vectors
+---------+---------+--------------+--------------+--------------+
|0 1 2 3 4|5 6 7 8 9|10 11 12 13 14|15 16 17 18 19|20 21 22 23 24|
|0 1 2 3 4|5 6 7 8 9|10 11 12 13 14|15 16 17 18 19|20 21 22 23 24|
|0 1 2 3 4|5 6 7 8 9|10 11 12 13 14|15 16 17 18 19|20 21 22 23 24|
|0 1 2 3 4|5 6 7 8 9|10 11 12 13 14|15 16 17 18 19|20 21 22 23 24|
|0 1 2 3 4|5 6 7 8 9|10 11 12 13 14|15 16 17 18 19|20 21 22 23 24|
+---------+---------+--------------+--------------+--------------+
   <"2 n *"0 (5 5 5 $ 1)  NB. multiply by scalars
+---------+---------+--------------+--------------+--------------+
|0 0 0 0 0|5 5 5 5 5|10 10 10 10 10|15 15 15 15 15|20 20 20 20 20|
|1 1 1 1 1|6 6 6 6 6|11 11 11 11 11|16 16 16 16 16|21 21 21 21 21|
|2 2 2 2 2|7 7 7 7 7|12 12 12 12 12|17 17 17 17 17|22 22 22 22 22|
|3 3 3 3 3|8 8 8 8 8|13 13 13 13 13|18 18 18 18 18|23 23 23 23 23|
|4 4 4 4 4|9 9 9 9 9|14 14 14 14 14|19 19 19 19 19|24 24 24 24 24|
+---------+---------+--------------+--------------+--------------+
```
You'll notice that this doesn't actually carve in the letters in the orientation the question asks for, it just writes them in however is convenient for rank logic. Unless we reverse or rotate the letters before we apply them, it won't work right. But correcting things like that would take up precious characters, so instead we'll encode the letters such that, when J carves them in naturally, *some* triple of faces will be in the correct orientations and relative positions. It turns out the shortest solution is to rotate all the letterforms a quarter-turn counterclockwise. Considering J's third dimension to represent the front-to-back axis, the crude diagram below shows why this scheme works.
![visualization of cube](https://i.stack.imgur.com/VeiVy.png) Figure A: The three sides of the cube that J carves into. Figure B: The three sides which have the letters oriented like the question asks.
This choice in encoding saves 12 characters over the previous method, and makes the whole thing neater. The actual golf creates the cube out of the `"1` and `"2` carves with some funky logic, due to an unrelated optimization.
Then we have to check the faces. Since we encode the block as 1s and 0s, we can just sum along each axis in the way we want (these are the `+/"1`, `+/"2`, and `+/` bits), adjust to booleans (`0<`), and then compare them all directly to the original 90°-turned-letters.
The compression scheme encodes each 5px row of each letter as the base 32 representation of a binary number. By exploiting a number of syntactic sugars and operator overloadings, `".'1b',"#:` is the shortest way to turn the list of characters into base 36 numbers. Well, technically, base 32, but J thinks it's unary, so who's counting?
Usage is below. Note that strings are character arrays in J, so a three item list `'A','B','C'` can be written `'ABC'` for short. Also, booleans are 1/0.
```
   NB. can be used inline...
   (_5#:\".'1b',"#:'fiiifalllvhhhheehhhvhhllvgkkkvnlhhvv444vhhvhhggvhjha44v1111vv848vv248vehhheciiivfjhhedmkkvilll9ggvggu111uo616ou121uha4ahg878ghpljh')((-:0<+/"1,+/"2,:+/)*`(*"1/)/)@:{~_65+3&u:'BEG'
1
   NB. or assigned to a name
   geb=:(_5#:\".'1b',"#:'fiiifalllvhhhheehhhvhhllvgkkkvnlhhvv444vhhvhhggvhjha44v1111vv848vv248vehhheciiivfjhhedmkkvilll9ggvggu111uo616ou121uha4ahg878ghpljh')((-:0<+/"1,+/"2,:+/)*`(*"1/)/)@:{~_65+3&u:
   geb 'BGE'
0
```
[Answer]
# Python, ~~687~~ ~~682~~ 671
```
import itertools as t,bz2
s=range(5)
c=dict([(i,1)for i in t.product(*3*[s])])
z=dict([(chr(i+65),[map(int,bz2.decompress('QlpoOTFBWSZTWXndUmsAATjYAGAQQABgADABGkAlPJU0GACEkjwP0TQlK9lxsG7aomrsbpyyosGdpR6HFVZM8bntihQctsSiOLrWKHHuO7ueAyiR6zRgxbMOLU2IQyhAEAdIJYB0ITlZwUqUlAzEylBsw41g9JyLx6RdFFDQEVJMBTQUcoH0DEPQ8hBhXBIYkXDmCF6E/F3JFOFCQed1Saw='.decode('base64')).split('\n')[j].split()[i])for j in s])for i in range(26)])
def m(a,g):
 for e in c:c[e]&=g[e[a]][e[a-2]]
def f(a):
 g=map(list,[[0]*5]*5)
 for e in c:g[e[a]][e[a-2]]|=c[e]
 return g
r=lambda g:map(list,zip(*g)[::-1])
def v(T,L,R):T,L,R=r(r(z[T])),r(z[L]),z[R];m(1,T);m(2,L);m(0,R);return(T,L,R)==(f(1),f(2),f(0))
```
Call with `v`:
```
v('B','E','G') => True
v('B','G','E') => False
```
Everything below is from my previous ungolfed version which includes helpful drawing functions. Feel free to use it as a jumping off point.
```
import string as s
import itertools as t
az = """01110  11110  01111  11110  11111  11111  11111  10001  11111  11111  10001  10000  10001  10001  01110  11110  01110  11110  01111  11111  10001  10001  10001  10001  10001  11111
10001  10001  10000  10001  10000  10000  10000  10001  00100  00100  10010  10000  11011  11001  10001  10001  10001  10001  10000  00100  10001  10001  10001  01010  01010  00010
10001  11110  10000  10001  11100  11110  10011  11111  00100  00100  11100  10000  10101  10101  10001  10001  10001  11111  01110  00100  10001  01010  10001  00100  00100  00100
11111  10001  10000  10001  10000  10000  10001  10001  00100  10100  10010  10000  10001  10011  10001  11110  10011  10010  00001  00100  10001  01010  10101  01010  00100  01000
10001  11110  01111  11110  11111  10000  11111  10001  11111  11100  10001  11111  10001  10001  01110  10000  01111  10001  11110  00100  01110  00100  01010  10001  00100  11111""".split('\n')
dim = range(len(az))
az = dict([(c, [map(int, az[j].split()[i]) for j in dim]) for i, c in enumerate(s.uppercase)])
cube = dict([(i, 1) for i in t.product(*3*[dim])])
def mask(axis, grid):
    for c in cube:
        if not grid[c[axis]][c[axis - 2]]:
            cube[c] = 0
def face(axis):
    grid = [[0 for j in dim] for i in dim]
    for c in cube:
        if cube[c]:
            grid[c[axis]][c[axis - 2]] = 1
    return grid
def rot(grid):
    return map(list, zip(*grid)[::-1])
def draw(grid, filled='X', empty=' '):
    s = ''
    for y in dim:
        for x in dim:
            s += filled if grid[y][x] else empty
        s += '\n'
    print s
def drawAll():
    print 'TOP:\n'
    draw(rot(rot(face(1))))
    print 'LEFT:\n'
    draw(rot(rot(rot(face(2)))))
    print 'RIGHT:\n'
    draw(face(0))
def valid(top, left, right):
    top, left, right = rot(rot(az[top])), rot(az[left]), az[right]
    mask(1, top)
    mask(2, left)
    mask(0, right)
    return top == face(1)and left == face(2) and right == face(0)
letters = 'BEG'
if valid(*letters):
    print letters, 'is valid.\n'
else:
    print letters, 'is not valid!\n'
drawAll()
```
Call `valid` to run it:
```
valid('B', 'E', 'G') #returns True
valid('B', 'G', 'E') #returns False
```
Right now the code is setup to test the validity of `B E G` and print out the resulting faces:
```
BEG is valid.
TOP:
XXXX 
X   X
XXXX 
X   X
XXXX 
LEFT:
XXXXX
X    
XXX  
X    
XXXXX
RIGHT:
XXXXX
X    
X  XX
X   X
XXXXX
```
Running it on `B G E` we can see that the G is incorrect:
```
BGE is not valid!
TOP:
XXXX 
X   X
XXXX 
X   X
XXXX 
LEFT:
XXXXX
X    
X  XX
X    
XXXXX
RIGHT:
XXXXX
X    
XXX  
X    
XXXXX
```
[Answer]
# [APL (Dyalog Unicode)](https://www.dyalog.com/), 150 [bytes](https://github.com/abrudz/SBCS)
```
x y z←(⎕A⍳⍞)⌷¨⊂26 5 5⍴(8⍴2)⊤⎕AV⍳'5∘⍉⍉c∨wÌþ∩⍀ýFó  â⍒⍪┤ÌÙÍ⊃?>áóU│yEå≥∧+├Û└KEÐ┐⌹;⍉ùigë/⋄⍪,ËwÙ4○$⊣7×c⍺þS¢|⍋îÜ⍀â:b⌷Î'
(x,y,z)≡(∨⌿,∨⌿⍤2,∨/)x×⍤2⊢z∘.×⍤1⊢y
```
[Try it online!](https://tio.run/##RVBdS8JgFMbb/YUu2kXgRitpZEVBUbBUuoy6N0MJhLrTjS7Covb1yoiFSRK6JllBNwvCIIOdf/L8EXtnYIfDOc/DeThfxbPqwrFerJ5WxjBvyuO6qIsGrj0JzbttsAjsUYb7GQ9gN9QVMStmwT6kNR5UGXaYqA65LJ2FeQ9mcS/BHNTIpRHMF7CLFH3vUhR34y4FYLdgr/BDXm4Tg325tUk9ig7gN/QZjfqw@jCf5@F36AG@v6eRB9@DO9zgjWl4UqG3DJwr3kQhp0btZbSc1Bzsp1VqlcC@aLQfB@dgziy9U4dPp2D9iK9PzbQg1RVdMWRYPYlvCPdH@UtgoZrAjFynVkJgBwa/ZnHCljjTk9eMxYmVhR0tJ0xxTpvifL7wjwv5Xw "APL (Dyalog Unicode) – Try It Online")
A full program that takes three uppercase letters from stdin and prints 0 (false) or 1 (true) to stdout.
We already have [an answer in J](https://codegolf.stackexchange.com/a/34877/78410) which has an excellent primer on multi-dimensional arrays and function rank. This answer uses the same concept. (Plus an obvious advantage that we can efficiently encode the binary arrays using the single-byte character encoding.)
### How it works
```
⍝ Extract the three bit matrices
x y z←(⎕A⍳⍞)⌷¨⊂26 5 5⍴(8⍴2)⊤⎕AV⍳'5∘⍉⍉c∨wÌþ∩⍀ýFó  â⍒⍪┤ÌÙÍ⊃?>áóU│yEå≥∧+├Û└KEÐ┐⌹;⍉ùigë/⋄⍪,ËwÙ4○$⊣7×c⍺þS¢|⍋îÜ⍀â:b⌷Î'
                            ⎕AV⍳'...'  ⍝ Char value of each char w.r.t. the code page
                      (8⍴2)⊤  ⍝ Convert each number to 8 bits, making 8-row matrix
               26 5 5⍴  ⍝ Take the bits and form 26×5×5 brick
      (⎕A⍳⍞)⌷¨⊂  ⍝ Take 3-char input and extract the corresponding 5×5 matrices
x y z←  ⍝ Assign to three variables
(x,y,z)≡(∨⌿,∨⌿⍤2,∨/)x×⍤2⊢z∘.×⍤1⊢y
                         z∘.×⍤1⊢y  ⍝ Combine front and right faces
                                   ⍝ so that three dimensions are oriented naturally
                    x×⍤2⊢  ⍝ Combine the top face
        (∨⌿,∨⌿⍤2,∨/)  ⍝ Compute the top, front, and right views of the pixels
(x,y,z)≡  ⍝ Check if they all match the original faces
```
[Answer]
# Python 3 + numpy, 327C
```
from numpy import*
B=hstack([ord(x)>>i&1for x in'옮弟ჹ羂옱쏷）ជ࿂︹缘龌ℿ쓥剴ℌᾄ起츱ꎚㆋឺ௣옮忬⧼ﯠႄ挒⺌ꕆ豈ꪱ袨冊䈑∾Ϣ'for i in range(16)])[:-6].reshape(26,5,5)
T=transpose
def f(*X):
 A=ones((5,5,5));F=list(zip([A,T(A,(1,0,2)),T(fliplr(A),(2,0,1))],[B[ord(x)-65]for x in X]))
 for r,f in F:r[array([f]*5)==0]=0
 return all([all(r.sum(0)>=f)for r,f in F])
```
This golf solution need an external library, numpy, which is quite popular so I think it's fine to use it.
The unicode string is in 41 chars, while the same thing in @fabian's prolog answer is 44.
The most interesting here is that the indexing of numpy array. In `a[ix]`, `ix` can be an boolean array with the same shape as `a`. It's the same as saying `a[i, j, k] where ix[i, j, k] == True`.
## Ungolfed Version
```
import numpy as np
table = '옮弟ჹ羂옱쏷）ជ࿂︹缘龌ℿ쓥剴ℌᾄ起츱ꎚㆋឺ௣옮忬⧼ﯠႄ挒⺌ꕆ豈ꪱ袨冊䈑∾Ϣ'
def expand_bits(x):
    return [ord(x) >> i & 1 for i in range(16)]
# B.shape = (26, 5, 5), B[i] is the letter image matrix of the i(th) char
B = np.hstack([expand_bits(x) for x in table])[:-6].reshape(26, 5, 5)
def f(*chars):
    """
    cube:    ----------   axis:           
            /         /|      --------->2  
           /   1     / |     /|            
          /         /  |    / |            
         /         /   |   /  |            
        |---------|  3 |  v   |           
        |         |    /  1   |           
        |    2    |   /       v          
        |         |  /        0         
        |         | /                  
        -----------
    """
    cube = np.ones((5, 5, 5))
    cube_views = [
        cube,
        cube.transpose((1, 0, 2)),  # rotate to make face 2 as face 1
        np.fliplr(cube).transpose(2, 0, 1),  # rotate to make face 3 as face 1
    ]
    faces = [B[ord(char) - ord('A')] for char in chars]
    # mark all white pixels as 0 in cube
    for cube_view, face in zip(cube_views, faces):
        # extrude face to create extractor
        extractor = np.array([face] * 5)
        cube_view[extractor == 0] = 0
    return np.all([
        # cube_view.sum(0): sum along the first axis
        np.all(cube_view.sum(0) >= face)
        for cube_view, face in zip(cube_views, faces)
    ])
```
## Script to compress table
```
import numpy as np
def make_chars():
    s = """
01110  11110  01111  11110  11111  11111  11111  10001  11111  11111  10001  10000  10001  10001  01110  11110  01110  11110  01111  11111  10001  10001  10001  10001  10001  11111
10001  10001  10000  10001  10000  10000  10000  10001  00100  00100  10010  10000  11011  11001  10001  10001  10001  10001  10000  00100  10001  10001  10001  01010  01010  00010
10001  11110  10000  10001  11100  11110  10011  11111  00100  00100  11100  10000  10101  10101  10001  10001  10001  11111  01110  00100  10001  01010  10001  00100  00100  00100
11111  10001  10000  10001  10000  10000  10001  10001  00100  10100  10010  10000  10001  10011  10001  11110  10011  10010  00001  00100  10001  01010  10101  01010  00100  01000
10001  11110  01111  11110  11111  10000  11111  10001  11111  11100  10001  11111  10001  10001  01110  10000  01111  10001  11110  00100  01110  00100  01010  10001  00100  11111
""".strip().split('\n')
    bits = np.zeros((26, 5, 5), dtype=np.bool)
    for c_id in range(26):
        for i in range(5):
            for j in range(5):
                bits[c_id, i, j] = s[i][j + c_id * 7] == '1'
    bits = np.hstack([bits.flat, [0] * 7])
    bytes_ = bytearray()
    for i in range(0, len(bits) - 8, 8):
        x = 0
        for j in range(8):
            x |= bits[i + j] << j
        bytes_.append(x)
    chars = bytes_.decode('utf16')
    return chars
```
]