Verifique se três letras podem formar um "cubo de Godel-Escher-Bach"

29

Esta questão é inspirada na capa do livro "Godel, Escher, Bach":

O desafio aqui é escrever uma função que diga se três letras dadas podem produzir uma escultura 3D que pode ser lida de três lados.

Para este exercício, as únicas letras que você pode usar são 26 bitmaps de 5px * 5px:

Ou em binário (A a 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

A escultura é formada por três letras na seguinte ordem:

  • letra uma em cima,
  • letra dois à esquerda
  • letra três à direita
  • a parte inferior da letra um está vinculada ao topo da letra dois.

Exemplo:

Sua função pode aceitar como entrada três letras maiúsculas (três caracteres ou três strings de uma letra) e gerar um booleano (verdadeiro / falso ou 0/1) informando se a escultura correspondente pode existir.

Exemplo:

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)

Nota: você pode retornar verdadeiro mesmo que a escultura contenha "pixels voadores" (cubos ou grupo de cubos que não estão anexados a nada).

Aplicam-se brechas padrão.

Mais precisamente, você não pode usar entrada externa além das três letras e não pode codificar as 17576 possíveis respostas no seu código-fonte

A resposta mais curta em caracteres em qualquer idioma vence!

Diverta-se :)

xem
fonte
Sim, é o quebra-cabeça da MU que me fez descobrir o livro, e é a capa do livro que me fez pensar nesse desafio. Existe algum problema? Isso fez parte dos seus 18 buracos?
Xem
2
Teria sido uma boa opção para substituir o orifício 1.;) ... Não importa, se alguma coisa é minha culpa por não ter levantado algo mais cedo. É um desafio realmente decente, +1!
Martin Ender
Podemos recuperar os dados que definem as formas das letras de um arquivo externo ou isso também precisa ser incluído na fonte?
CesiumLifeJacket
Seu B binário tem 0 no canto superior esquerdo, não 1.
Calvin's Hobbies

Respostas:

13

Mathematica 423

Eu adicionei uma seção chamada "Como funciona o bloqueio".

Ungolfed

(* Os dados binários do alfabeto são armazenados como uma única string em s. Os varsimporta e os converte em uma matriz.)

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]

Exemplo

O cubo é {"B", "G", "E"}válido? (ou seja, as três letras se projetam corretamente nas paredes?)

validQ[{"B", "G", "E"}]

Falso

Ilustrações

As figuras abaixo mostram como a BGE é renderizada. A linha superior das figuras tem perspectivas ortogonais, como se o espectador estivesse posicionado a distâncias infinitas do cubo. A linha inferior mostra a aparência dos blocos de perto. As figuras 3D podem ser giradas manualmente para inspecionar com precisão onde os cubos de unidades individuais estão posicionados.

Ocorre um problema com a letra "G". Não há nada conectando a serifa ao restante da carta.

pts = {{"B", 3, 0}, {"G", 2, 0}, {"E", 1, 0}}
GraphicsGrid@Partition[Table[perspective[pts, view], {view, 1, 6}], 3]

bge


No entanto, o BEG deve funcionar bem.

 validQ[{"B", "E", "G"}]

Verdade

pts2 = {{"B", 3, 0}, {"E", 2, 0}, {"G", 1, 0}}
GraphicsGrid@Partition[Table[perspective[pts2, view], {view, 1, 6}], 3]

implorar


Como funciona o bloqueio?

Por favor, desculpe-me se isso parecer óbvio, mas talvez algumas pessoas desejem visualizar como as letras interferem umas nas outras, cancelando seus pixels 3D.

Vamos seguir o que acontece com a letra G, na renderização do cubo BGE.

Vamos prestar atenção especial ao voxel (pixel 3D ou cubo unitário) abaixo. Esse é o pixel que desaparece no cubo BGE. É o pixel correspondente à Linha 4, Coluna 5 na matriz de bits e no gráfico da matriz correspondente.

bloqueio 1


No plano xy, o pixel corresponde ao disco cinza no ponto (5,2). Mas como vamos trabalhar em 3D, precisamos considerar as 5 posições no eixo de (5,1,2) a (5,5,2). Se algum desses pixels sobreviver à escultura pelas letras B e E, poderemos ver o pixel de interesse na projeção 3D na parede.

bloqueio 2


As letras interferem quando os pixels são removidos do bloco sólido. À esquerda, a seta preta representa a escultura de pixels, correspondente ao bit no canto inferior direito; ele tem o valor 0 para a letra B. A remoção remove o pixel em (5,1,2), junto com os diretamente acima e abaixo dele. Ainda faltam quatro pixels para serem contabilizados.

bloqueio 3

Mas, como mostra o painel direito, a letra E esculpe os pixels restantes de interesse, (5,2,2) (5,3,2), (5,4,2) e (5,5,2). (Isso se deve ao fato de a letra E ter bits iguais a 0 na quarta linha, da coluna 2 à coluna 5.) Como resultado, nenhum pixel permanece entre os necessários para garantir a sombra no ponto (5). , 2) na parede oposta (para a letra G). Em vez disso, haverá um ponto brilhante correspondente a um buraco na letra G! O cubo BGE não é bom porque renderiza incorretamente G.

Golfe 423 caracteres

A função hteve o mesmo papel que validQno código não-Golped. A função de renderização,, perspectivenão está incluída porque não contribui para o desafio e não é exigida por ele.

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}}]
DavidC
fonte
Uau, essas visualizações em 3D são muito legais! Você tem certeza de que o último bloco de código é "UnGolfed"? Parece-me jogar golfe. :)
xem
Você está certo. O bloco final é jogado no golfe. Corrigi o cabeçalho. Uma coisa interessante das visualizações em 3D é que elas são interativas: rotação e zoom podem ser feitos com o mouse.
19414
BTW, pela minha conta, existem 564 cubos válidos entre as 15600 permutações possíveis.
19414
Essa é uma informação legal. Quanto tempo você levou para calcular isso? também, 26 * 26 * 26 = 17576, não 15600. Ou estou faltando alguma coisa?
xem
Eu usei permutações, não tuplas; ou seja, sem letras repetidas. 26 * 25 * 24 = 15600. Foram necessários 21 segundos para encontrar os 564 casos.
19414
12

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.

O programa é chamado assim:

?- f('B','E','G').
true.
?- f('B','G','E').
false.

Prologparecia ser uma boa escolha, pois é fácil representar o problema na lógica de primeira ordem. Também Prologfornece funcionalidade potente para resolver esse tipo de problema.

No entanto, como o código é golfado, acho que devo adicionar alguma explicação.

Versão levemente golfe

:- 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.

As coordenadas correspondentes aos pixels em cada lado dos dados podem ser facilmente convertidas em um sistema de coordenadas 3D. Eu uso T, Le Rpara cima (1), à esquerda (2) e lateral direita (3). ue vsão usados ​​para as coordenadas nas imagens:

  • T :(u,v) -> (4-v, ?, u)
  • L :(u,v) -> (?, v, u)
  • R :(u,v) -> (u, v, ?)

Os resultados para cada pixel ativo (ou seja, preto) são combinados com um conjunto de "pixels 3D" que podem ser ativados sem alterar a aparência do objeto desse lado. A interseção dos conjuntos para cada lado é composta por pixels 3D, que podem ser ativados sem a adição de pixels, que obstruiriam a visualização (ou seja, olhando de pelo menos um lado, haveria um pixel que não deveria estar lá).

Tudo o que resta é verificar para cada lado, se há um pixel na interseção que bloqueia a visualização, onde é necessário.

Isso leva aos predicados do programa:

  • f : faz a verificação final; pega as letras no topo, no lado esquerdo e no lado direito
  • u , v e w : faz as verificações, se para cada pixel ativo no lado houver um pixel 3D na interseção, que bloqueia a visualização
  • h : verifica a existência de um pixel na interseção
  • t , l , r : verifica se um pixel 3D pode ser bloqueado do lado superior, esquerdo e direito.
  • c : verifica o pixel na imagem de uma letra. A cadeia de caracteres pode parecer um pouco estranha, mas é apenas uma maneira compacta de armazenar os dados da imagem. É simplesmente uma sequência de caracteres com os seguintes valores (notação hexadecimal):

    [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]
    

    Cada um desses caracteres armazena os dados de 3 linhas de pixel na (s) imagem (s) da letra (= 15 pixels). Os pixels também são reordenados para que os dados sejam armazenados em um local e não divididos em várias linhas, como os dados do OP.

Formulação matemática

Fórmula

Dados de entrada

Fórmula

Conversão de pixel em um caractere para o conjunto de pixels 3D que obstruem a visualização desse pixel

Fórmula

Fórmula

Fórmula

Pixels que podem ser adicionados com segurança (sem obstruir a exibição no lugar errado)

Fórmula

Verifica para cada lado, se os pixels que precisam ser obstruídos podem ser obstruídos com segurança

Fórmula

Fórmula

Fórmula

Combinação de verificações para cada lado

Fórmula

fabiano
fonte
11
Eu .. O que? Eu acho isso incompreensível. (+1)
ver
Santo ... eu estou indo para a cama ...
BrunoJ 16/07
Impressionante! Obrigado por esta resposta
xem
11
Agradável. Aliás, penso no processo como começando com um bloco cúbico sólido. (Você parece pensar em adicionar pixels onde não havia antes.) Cada letra remove alguns pixels 3D desse bloco. Portanto, a interferência ocorre quando uma letra vizinha remove pixels que uma letra "queria manter". A interferência decorre de "pixels ausentes" em vez de pixels extras.
19414
9

J - 223 197 191 carvão

Uma função que usa uma lista de três caracteres como argumento.

(_5#:\".'1b',"#:'fiiifalllvhhhheehhhvhhllvgkkkvnlhhvv444vhhvhhggvhjha44v1111vv848vv248vehhheciiivfjhhedmkkvilll9ggvggu111uo616ou121uha4ahg878ghpljh')((-:0<+/"1,+/"2,:+/)*`(*"1/)/)@:{~_65+3&u:

Esse golfe depende muito de um recurso poderoso de J chamado rank , que nos dá as operações de "esculpir" e "assistir" das operações quase de graça. Para simplificar um pouco, a classificação se refere à dimensionalidade de um substantivo ou dos argumentos naturais de um verbo.

J possui matrizes multidimensionais e é óbvio que, digamos, uma matriz 3D pode ser interpretada como uma única matriz 3D, ou como uma lista de matrizes, ou uma matriz 2D de vetores, ou uma matriz 3D de escalares. Portanto, toda operação em J pode ter sua aplicação controlada, através de como se espalhar sobre o argumento. A classificação 0 significa aplicar nos escalares, a classificação 1 significa aplicar nos vetores e assim por diante.

   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

Isso se torna muito poderoso quando você introduz funções diádicas (dois argumentos), porque se as formas dos dois argumentos (após contabilizar a classificação) são agradáveis, J fará alguns ciclos implícitos:

   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

Quando todas as suas formas são agradáveis ​​e você mesmo pode especificar a classificação, existem várias maneiras de combinar argumentos. Aqui, mostramos algumas das maneiras pelas quais você pode multiplicar uma matriz 2D e uma matriz 3D.

   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|
+---------+---------+--------------+--------------+--------------+

Você notará que isso não está realmente gravado nas letras na orientação solicitada, apenas as escreve, mas é conveniente para a lógica de classificação. A menos que revertamos ou rotacionemos as letras antes de aplicá-las, elas não funcionarão corretamente. Mas corrigir coisas assim ocuparia caracteres preciosos; portanto, codificaremos as letras de modo que, quando J as esculpir naturalmente, algumas faces triplas estarão nas orientações corretas e nas posições relativas. Acontece que a solução mais curta é girar todas as formas de letras um quarto de volta no sentido anti-horário. Considerando a terceira dimensão de J para representar o eixo da frente para trás, o diagrama bruto abaixo mostra por que esse esquema funciona.

visualização de cubo Figura A: Os três lados do cubo em que J esculpe. Figura B: Os três lados que têm as letras orientadas como a pergunta.

Essa opção de codificação salva 12 caracteres em relação ao método anterior e torna a coisa toda mais organizada. O golfe real cria o cubo a partir do"1 e "2esculpe com alguma lógica descolada, devido a uma otimização não relacionada.

Então temos que verificar os rostos. Desde que codificar o bloco como 1s e 0s, podemos simplesmente somar ao longo de cada eixo da maneira que queremos (estes são a +/"1, +/"2e,+/ bits), ajuste a booleans ( 0<), e depois compará-los todos diretamente para o original 90 ° - virou letras.

O esquema de compactação codifica cada linha de 5px de cada letra como a representação base 32 de um número binário. Ao explorar vários açúcares sintáticos e sobrecargas do operador,".'1b',"#: é a maneira mais curta de transformar a lista de caracteres em números de base 36. Bem, tecnicamente, a base 32, mas J acha que é unário, então quem está contando?

O uso está abaixo. Observe que cadeias de caracteres são matrizes de caracteres em J; portanto, uma lista de três itens 'A','B','C'pode ser escrita 'ABC'para abreviar. Além disso, os booleanos são 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
algoritmshark
fonte
4

Pitão, 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))

Ligue para v:

v('B','E','G') => True
v('B','G','E') => False

Tudo abaixo é da minha versão ungolfed anterior, que inclui funções úteis de desenho. Sinta-se livre para usá-lo como um ponto de partida.

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()

Ligue validpara executá-lo:

valid('B', 'E', 'G') #returns True
valid('B', 'G', 'E') #returns False

No momento, o código está configurado para testar a validade B E Ge imprimir as faces resultantes:

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

Ao executá-lo B G E, podemos ver que o G está incorreto:

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
Passatempos de Calvin
fonte
uau, bom trabalho! +1 para drawAll e a integridade da resposta. +1 por usar um algoritmo tão curto. <3 it
xem
@xem Obrigado! Eu finalmente joguei. Embora eu não tenha conseguido descobrir como fazer o bz2 descomprimir caracteres unicode.
Hobbies de Calvin
+1. Boa resposta. Espero que mais pessoas votem em golfe menores, como este, porque é preciso muito esforço.
Vetorizado
11
g=[[0 for j in s]for i in s]pode ser reduzido para g=map(list,[[0]*5]*5). Além disso, você pode evitar o recuo blocos se eles são uma única instrução: if c[e]:g[e[a]][e[a-2]]=1.
Bakuriu 15/07/2014
@Bakuriu e bitpwner, obrigado pelas sugestões e edições :)
de Calvino Hobbies
1

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])

Esta solução de golfe precisa de uma biblioteca externa, numpy, que é bastante popular, então eu acho que é bom usá-la.

A string unicode está em 41 caracteres, enquanto a mesma coisa na resposta do prólogo do @ fabian é 44.

O mais interessante aqui é que a indexação da matriz numpy. In a[ix], ixpode ser uma matriz booleana com a mesma forma que a. É o mesmo que dizera[i, j, k] where ix[i, j, k] == True .

Versão Ungolfed

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 para compactar tabela

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
Raio
fonte