El obispo borracho

42

En la criptografía de clave pública, una huella digital de clave pública es una secuencia corta de bytes utilizada para identificar una clave pública más larga.

En SSH, en particular, se pueden usar para verificar que un servidor es de hecho el servidor con el que espero comunicarme y que no soy el objetivo de un ataque de hombre en el medio.

Por lo general, se representan como una cadena de dígitos hexadecimales, por lo que puede ser bastante aburrido y tedioso compararlo con la huella digital que esperaría:

37:e4:6a:2d:48:38:1a:0a:f3:72:6d:d9:17:6b:bd:5e

Para hacerlo un poco más fácil, OpenSSH ha introducido un método para visualizar huellas digitales como arte ASCII, que se vería así:

+-----------------+
|                 |
|                 |
|          .      |
|     .   o       |
|o . o . S +      |
|.+ + = . B .     |
|o + + o B o E    |
| o .   + . o     |
|         .o      |
+-----------------+

Con esto, podría tratar de recordar la forma aproximada del arte ASCII y luego (teóricamente) lo reconocería cuando la huella digital del servidor cambiara y la imagen se viera diferente.

Cómo funciona

Tomado de Dirk Loss, Tobias Limmer, Alexander von Gernler. 2009. El obispo borracho: un análisis del algoritmo de visualización de huellas digitales OpenSSH .

La cuadrícula tiene un ancho de 17 caracteres y una altura de 9 caracteres. El "obispo" comienza en la fila 4 / columna 8 (el centro). Cada posición se puede denotar como [x, y], es decir, [8,4] para la posición inicial del obispo.

            1111111
  01234567890123456
 +-----------------+
0|                 |
1|                 |
2|                 |
3|                 |
4|        S        |
5|                 |
6|                 |
7|                 |
8|                 |
 +-----------------+

El obispo usa la huella digital para moverse. Lo lee en bytes de izquierda a derecha y del bit menos significativo al bit más significativo:

Fingerprint      37      :       e4      :       6a      :  ...  :       5e
Bits        00 11 01 11  :  11 10 01 00  :  01 10 10 10  :  ...  :  01 01 11 10
             |  |  |  |      |  |  |  |      |  |  |  |              |  |  |  |
Step         4  3  2  1      8  7  6  5     12 11 10  9             64 63 62 61

El obispo se moverá según el siguiente plan:

Bits   Direction
-----------------
00     Up/Left
01     Up/Right
10     Down/Left
11     Down/Right

Casos especiales:

  • Si el obispo está en una esquina y volvería a moverse hacia la esquina, no se mueve en absoluto. es decir: el obispo está en [0,0]y su próximo paso sería 00. El permanece en[0,0]
  • Si el alfil está en una esquina o en una pared y se mudaría a una de las paredes, se mueve solo horizontal o verticalmente. es decir: el obispo está en [0,5]y su próximo paso sería 01. No puede ir a la izquierda, así que simplemente se mueve hacia arriba [0,4].

Cada posición tiene un valor de la frecuencia con que el obispo ha visitado este campo:

Value      | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10| 11| 12| 13| 14| 15| 16|
Character  |   | . | o | + | = | * | B | O | X | @ | % | & | # | / | ^ | S | E |

Los valores 15 (S) y 16 (E) son especiales porque marcan la posición inicial y final del alfil respectivamente y sobrescriben el valor real de la posición de respeto.

Gol

Cree un programa que tome una huella digital alfanumérica como entrada y produzca su representación artística ASCII como se muestra en los ejemplos.

Ejemplos

Input:
16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48

Output:
+-----------------+
|        .        |
|       + .       |
|      . B .      |
|     o * +       |
|    X * S        |
|   + O o . .     |
|    .   E . o    |
|       . . o     |
|        . .      |
+-----------------+

Input:
b6:dd:b7:1f:bc:25:31:d3:12:f4:92:1c:0b:93:5f:4b

Output:
+-----------------+
|            o.o  |
|            .= E.|
|             .B.o|
|              .= |
|        S     = .|
|       . o .  .= |
|        . . . oo.|
|             . o+|
|              .o.|
+-----------------+

Input:
05:1e:1e:c1:ac:b9:d1:1c:6a:60:ce:0f:77:6c:78:47

Output:
+-----------------+
|       o=.       |
|    o  o++E      |
|   + . Ooo.      |
|    + O B..      |
|     = *S.       |
|      o          |
|                 |
|                 |
|                 |
+-----------------+

Reglas

  • Este es el . El código en la menor cantidad de bytes gana.
  • Puede no utilizar una biblioteca existente que produce la imagen.
  • ¡Usa el idioma que prefieras!
  • Su envío tiene que ser un programa completo
Padarom
fuente
3
¿Podemos suponer que ninguna celda será visitada más de 14 veces?
Martin Ender
2
Hay algunos casos de esquina de cobertura mínima que resultarían en la visita de algunos campos más de 14 veces. 33:33:33:...:33, cc:cc:cc:...:ccserían ejemplos para esto. La huella digital generalmente es un hash MD5, por lo que es muy poco probable que obtenga ese resultado. No he encontrado ninguna fuente confiable sobre cómo lidiar con esto, por lo que por ahora diría: Suponga que no se visitará ninguna celda más de 14 veces.
Padarom

Respuestas:

2

Pyth, 125 bytes

Jj*17\-"++"JVc9XXsm@"^ .o+=*BOX@%&#/"hdrS+*U9U17K.u.e@S[0b*8hk)1.b+tNyYNYsm_c4.[08jxsM^.HM16 2d2cz\:,4 8 8ieK17\E76\SjN"||")J

Pruébelo en línea: Demostración o Test-Suite

Escribí hace unos días, pero no lo publiqué, porque no estaba muy contento con eso.

Explicación:

La idea básica es la siguiente. Empiezo con la pareja (4, 8). En cada movimiento (m1,m2)voy del (x, y)al (x-1+2*m1, y-1+2*m2). Para asegurarse de que estas coordenadas no salen fuera de las fronteras, voy a hacer algunas listas, clasificar y regresar el elemento central: (sorted(0,8,newx)[1], sorted(0,16,newy)[1]).

Realizo un seguimiento de todas las posiciones. A esta lista de posiciones agrego una lista de todas las posiciones posibles, las ordeno y las codifico por longitud de ejecución. Lo que me da un número para cada posición. Con este número, puedo elegir el carácter coherente y, al final, sobrescribir los caracteres de la posición inicial y final.

Jakube
fuente
9

Dyalog APL (178)

{⎕ML←3⋄F←9 17⍴0⋄5 9{(⍺⌷F)+←1⋄×⍴⍵:(1 1⌈9 17⌊⍺-1 1-2×↑⍵)∇1↓⍵⋄(⍺⌷F)←16⋄F[5;9]←15⋄K⍪(M,' .o+=*BOX@%&#/^SE'[1+F],M←'|')⍪K←'+','+',⍨17⍴'-'}⊃,/{↓⊖4 2⍴⍉(4/2)⊤¯1+⍵⍳⍨⎕D,'abcdef'}¨⍵⊂⍨':'≠⍵}

Esta es una función que toma la cadena como argumento correcto y devuelve una matriz de caracteres que contiene la representación de arte ASCII, por ejemplo:

      F←{⎕ML←3⋄F←9 17⍴0⋄5 9{(⍺⌷F)+←1⋄×⍴⍵:(1 1⌈9 17⌊⍺-1 1-2×↑⍵)∇1↓⍵⋄(⍺⌷F)←16⋄F[5;9]←15⋄K⍪(M,' .o+=*BOX@%&#/^SE'[1+F],M←'|')⍪K←'+','+',⍨17⍴'-'}⊃,/{↓⊖4 2⍴⍉(4/2)⊤¯1+⍵⍳⍨⎕D,'abcdef'}¨⍵⊂⍨':'≠⍵}


      F '16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48'
+-----------------+
|        .        |
|       + .       |
|      . B .      |
|     o * +       |
|    X * S        |
|   + O o . .     |
|    .   E . o    |
|       . . o     |
|        . .      |
+-----------------+
      F 'b6:dd:b7:1f:bc:25:31:d3:12:f4:92:1c:0b:93:5f:4b'
+-----------------+
|            o.o  |
|            .= E.|
|             .B.o|
|              .= |
|        S     = .|
|       . o .  .= |
|        . . . oo.|
|             . o+|
|              .o.|
+-----------------+

Explicación:

  • ⎕ML←3: establecido ⎕MLen 3. Esto lo hace más útil para dividir cadenas.

  • F←9 17⍴0: crea una matriz de ceros de 17 por 9. Frepresenta cuántas veces se ha visitado cada puesto.

  • ⍵⊂⍨':'≠⍵: dividido en :personajes.

  • {... : para cada grupo:
    • ¯1+⍵⍳⍨⎕D,'abcdef': encuentra el índice de cada carácter en la cadena '01234567890abcdef'. Reste 1, porque APL está indexado en 1 por defecto.
    • (4/2)⊤: convierte los valores a sus representaciones de 4 bits (ahora debería haber una matriz de 2 por 4).
    • ↓⊖4 2⍴⍉: gire la matriz, use los elementos para llenar una matriz de 2 por 4 en su lugar, refleje esa matriz horizontalmente y luego obtenga cada línea por separado. Esto nos da los 4 valores de 2 bits que necesitamos.
  • ⊃,/: une las listas resultantes, dando una lista de pasos de 2 bits.
  • 5 9{... }: dada la lista de pasos, y comenzando en la posición [9,5]:
    • (⍺⌷F)+←1: incrementa la posición actual en F.
    • ×⍴⍵:: si la lista de pasos no está vacía:
      • ↑⍵: da el primer paso de la lista
      • ⍺-1 1-2×: obtener el delta para ese paso y restarlo de la posición actual
      • 1 1⌈9 17⌊: restringir el movimiento dentro del campo
      • (... )∇1↓⍵: continúe con la nueva posición y el resto de los pasos
    • Si está vacío:
      • (⍺⌷F)←16: establecido Fen 16 en la posición final
      • F[5;9]←15: establecido Fen 15 en la posición inicial
      • ' .o+=*BOX@%&#/^SE'[1+F]: asigna cada posición al personaje correspondiente
      • K⍪(M,... ,M←'|')⍪K←'+','+',⍨17⍴'-': ajusta el resultado en líneas
marinus
fuente
8

Perl, 300 + 1 (-n) = 301 bytes

perl -ne 'sub b{$b=$_[0]+$_[1];$_[0]=$b<0?0:$b>$_[2]?$_[2]:$b}$v=pack"(H2)*",/\w\w/g;($x,$y)=(8,4);$a[b($y,($_&2)-1,8)*17+b($x,($_&1)*2-1,16)]++for map{vec$v,$_,2}0..63;@a[76,$y*17+$x]=(15,16);$c=" .o+=*BOX@%&#/^SE";print$d="+".("-"x17)."+\n",(map{+"|",(map{substr$c,$_,1}@a[$_*17..($_+1)*17-1]),"|\n"}0..8),$d'

Esta respuesta es asquerosa, pero también es la primera para este acertijo, por lo que lo hará por ahora.

-ntomar una línea de entrada en STDIN y llenar $_.

# b($v, -1 or 1, max) modifies $v within 0..max
sub b{$b=$_[0]+$_[1];$_[0]=$b<0?0:$b>$_[2]?$_[2]:$b}

# turn $_ into a binary string
$v=pack"(H2)*",/\w\w/g;

# initialize cursor
($x,$y)=(8,4);

# find an element of single-dimensional buffer @a
$a[
    # y += (bitpair & 2) - 1, within 8
    b($y,($_&2)-1,8) * 17
    # x += (bitpair & 1) * 2 - 1, within 17
  + b($x,($_&1)*2-1,16)
# and increment it
]++
# for each bit pair (in the right order!)
  for map{vec$v,$_,2}0..63;

# overwrite the starting and ending positions
@a[76,$y*17+$x]=(15,16);

# ascii art lookup table
$c=" .o+=*BOX@%&#/^SE";

# output
print
  # the top row, saving it for later
  $d="+".("-"x17)."+\n",
  # each of the eight middle rows
  (map{+
    # converting each character in @a in this row as appropriate
    "|",(map{substr$c,$_,1}@a[$_*17..($_+1)*17-1]),"|\n"
  }0..8),
  # the bottom row
  $d
Eric Wastl
fuente
7

R, 465 459 410 393 382 357 bytes

f=function(a){s=strsplit;C=matrix(as.integer(sapply(strtoi(el(s(a,":")),16),intToBits)[1:8,]),2);C[!C]=-1;n=c(17,9);R=array(0,n);w=c(9,5);for(i in 1:64){w=w+C[,i];w[w<1]=1;w[w>n]=n[w>n];x=w[1];y=w[2];R[x,y]=R[x,y]+1};R[]=el(s(" .o+=*BOX@%&#/^",""))[R+1];R[9,5]="S";R[x,y]="E";z="+-----------------+\n";cat(z);for(i in 1:9)cat("|",R[,i],"|\n",sep="");cat(z)}

Con hendiduras y nuevas líneas:

f=function(a){
    s=strsplit
    C=matrix(as.integer(sapply(strtoi(el(s(a,":")),16),intToBits)[1:8,]),2)
    C[!C]=-1
    n=c(17,9)
    R=array(0,n)
    w=c(9,5)
    for(i in 1:64){
        w=w+C[,i]
        w[w<1]=1
        w[w>n]=n[w>n]
        x=w[1]
        y=w[2]
        R[x,y]=R[x,y]+1
    }
    R[]=el(s(" .o+=*BOX@%&#/^",""))[R+1]
    R[9,5]="S"
    R[x,y]="E"
    z="+-----------------+\n"
    cat(z)
    for(i in 1:9)cat("|",R[,i],"|\n",sep="")
    cat(z)
}

Uso:

> f("16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48")
+-----------------+
|        .        |
|       + .       |
|      . B .      |
|     o * +       |
|    X * S        |
|   + O o . .     |
|    .   E . o    |
|       . . o     |
|        . .      |
+-----------------+
> f("37:e4:6a:2d:48:38:1a:0a:f3:72:6d:d9:17:6b:bd:5e")
+-----------------+
|                 |
|                 |
|          .      |
|     .   o       |
|o . o . S +      |
|.+ + = . B .     |
|o + + o B o E    |
| o .   + . o     |
|         .o      |
+-----------------+
plannapus
fuente
¿No puede jugar golf la función 'matriz' definiéndola una vez como 'm'? ¿Lo mismo para 'función'?
CousinCocaine
Creo que no necesita 'sep =' en la función 'cat'
CousinCocaine
el valor predeterminado para sep es un espacio, por lo que necesito anularlo, pero de hecho podría alias matrix.
plannapus
Además, por lo que sé, no puedes alias function.
plannapus
5

Octava, 277

d=reshape(rot90(dec2bin(hex2dec(strsplit(input('','s'),':'))))>'0',2,[])*2-1;p=[9;5];for m=1:64 p=[max(min(p(:,1)+d(:,m),[17;9]),1) p];end;A=' .o+=*BOX@%&#/^SE';F=A(sparse(p(2,:),p(1,:),1,9,17)+1);F(5,9)='S';F(p(2,1),p(1,1))='E';[a='+-----------------+';b=['|||||||||']' F b;a]

Explicación:

%// convert the input to binary and rearrange it to be
%//   an array of vectors: [x_displacement; y_displacement]
d=reshape(rot90(dec2bin(hex2dec(strsplit(input('','s'),':'))))>'0',2,[])*2-1;

%// start position array with vector for the start position
p=[9;5];
%// for each move, add displacement, clamping to valid values
for m=1:64 p=[max(min(p(:,1)+d(:,m),[17;9]),1) p];end;

%// alphabet for our fingerprint
A=' .o+=*BOX@%&#/^SE';

%// create a sparse matrix, accumulating values for duplicate
%// positions, and replace counts with symbols
F=A(sparse(p(2,:),p(1,:),1,9,17)+1);

%// correct the start and end symbols and construct the final output
F(5,9)='S';F(p(2,1),p(1,1))='E';
[a='+-----------------+';b=['|||||||||']' F b;a]

Ejecución de muestra:

>> bish
b6:dd:b7:1f:bc:25:31:d3:12:f4:92:1c:0b:93:5f:4b
ans =

+-----------------+
|            o.o  |
|            .= E.|
|             .B.o|
|              .= |
|        S     = .|
|       . o .  .= |
|        . . . oo.|
|             . o+|
|              .o.|
+-----------------+
cubilete
fuente
3

Pyth, 145 143 140

Jm*17]09A,4K8FYcz\:V4AmhtS[0^2d+@,HGdtyv@+_.BiY16*7\0+-4dyN),3 4 X@JGHh@@JGH; X@J4K15 X@JGH16
=Y++\+*17\-\+VJ++\|s@L" .o+=*BOX@%&#/^SE"N\|)Y

Pruébalo en línea.

Pyth no es realmente bueno en los desafíos con la iteración. Espero que CJam lo supere fácilmente.

PurkkaKoodari
fuente
3

JavaScript (ES6) 249 208

Editar borde faltante agregado

Pruebe a ejecutar el fragmento a continuación en cualquier navegador compatible con EcmaScript 6

B=f=>f.replace(/\w+/g,b=>{for(b=`0x1${b}`;b-1;b>>=2)++g[p=(q=(p=(q=p+~-(b&2)*18)>0&q<162?q:p)+b%2*2-1)%18?q:p]},p=81,z=`+${'-'.repeat(17)}+`,g=Array(162).fill(0))&&g.map((v,q)=>q?q-81?q-p?q%18?' .o+=*BOX@%&#/^'[v]:`|
|`:'E':'S':z+`
|`).join``+`|
`+z

// TEST
console.log=x=>O.innerHTML+=x+'\n'

;['37:e4:6a:2d:48:38:1a:0a:f3:72:6d:d9:17:6b:bd:5e'
,'16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48'
,'b6:dd:b7:1f:bc:25:31:d3:12:f4:92:1c:0b:93:5f:4b'
,'05:1e:1e:c1:ac:b9:d1:1c:6a:60:ce:0f:77:6c:78:47'  
].forEach(t=>console.log(t+'\n'+B(t)+'\n'))


// Less golfed

BB=f=>(
  p = 81,
  g = Array(162).fill(0),
  f.replace(/\w+/g, b => {
    for(b = `0x1${b}`;b != 1; b >>= 2)
      q = p+~-(b&2)*18,
      p = q>0&q<162?q:p,
      p = (q=p+b%2*2-1)%18?q:p,
      ++g[p]
  }),
  g.map((v,q) => q-81?q-p?q%18?' .o+=*BOX@%&#/^'[v]:'\n':'E':'S')
  .join``
)
pre { font-family: menlo,consolas; font-size:13px }
<pre id=O></pre>

edc65
fuente
Su código de golf debería ser capaz de imprimir los bordes también. Actualmente, solo su caso de prueba imprime los bordes superior e inferior en el forEach, aún faltan los bordes verticales.
Padarom
@Padarom No entendí tu comentario de "sé razonable", pensando que no se solicitó la frontera
edc65
Me refería a ser razonable en cuanto a qué método de entrada y salida utiliza. Mis disculpas si eso fue engañoso, lo
editaré
3

Python, 381 328

-51 gracias a @JonathanFrech

def h(f):
 s=[f'{int(o,16)>>s&3:02b}'for o in f.split(':')for s in(0,2,4,6)];r=[0]*153;p=76;w=17
 for d in s:r[p]+=1;p+=(-(p%w!=0),p%w!=16)[int(d[1])]+(-w*(p//w!=0),w*(p//w!=8))[int(d[0])]
 r[76]=15;r[p]=16;b='+'+'-'*w+'+';print(b);i=0
 while i<153:print(f"|{''.join(' .o+=*BOX@%&#/^SE'[c]for c in r[i:i+w])}|");i+=w
 print(b)

Ligeramente poco golfista por el bien de la explicación:

def h_(f):
 #Alias 17 because it gets used enough times for this to save bytes
 w=17

 #Input parsing
 s=[f'{int(o,16)>>s&3:02b}'for o in f.split(':')for s in(0,2,4,6)]

 #Room setup
 r=[0]*153
 p=76

 #Apply movements
 for d in s:
  r[p]+=1
  p+=(-(p%w!=0),p%w!=16)[int(d[1])]+(-w*(p//w!=0),w*(p//w!=8))[int(d[0])]
 r[76]=15 #Set start position
 r[p]=16 #Set end position

 #Display result
 b='+'+'-'*w+'+'
 print(b)
 i=0
 while i<153:
  print(f"|{''.join(' .o+=*BOX@%&#/^SE'[c]for c in r[i:i+w])}|")
  i+=w
 print(b)

Este lío de una línea:

r[p]+=1;p+=(-(p%w!=0),p%w!=16)[int(d[1])]+(-w*(p//w!=0),w*(p//w!=8))[int(d[0])]

Es funcionalmente equivalente a esto:

if int(d[0]): #Down, Y+
  if p//17!=8:
    p+=17
else: #Up, Y-
  if p//17!=0:
    p-=17
​
if int(d[1]): #Right, X+
  if p%17!=16:
    p+=1
else: #Left, X-
  if p%17!=0:
    p-=1

pero anida todos los condicionales en este estilo de atajo de golf: (false_value,true_value)[condition] espero que el resto se explique por sí solo

Pruebas

h('16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48')
+-----------------+
|        .        |
|       + .       |
|      . B .      |
|     o * +       |
|    X * S        |
|   + O o . .     |
|    .   E . o    |
|       . . o     |
|        . .      |
+-----------------+

h("b6:dd:b7:1f:bc:25:31:d3:12:f4:92:1c:0b:93:5f:4b")
+-----------------+
|            o.o  |
|            .= E.|
|             .B.o|
|              .= |
|        S     = .|
|       . o .  .= |
|        . . . oo.|
|             . o+|
|              .o.|
+-----------------+

h("05:1e:1e:c1:ac:b9:d1:1c:6a:60:ce:0f:77:6c:78:47")
+-----------------+
|       o=.       |
|    o  o++E      |
|   + . Ooo.      |
|    + O B..      |
|     = *S.       |
|      o          |
|                 |
|                 |
|                 |
+-----------------+
```
senox13
fuente
Hola y bienvenidos a PPCG. Puede jugar golf su código utilizando nombres de variables de una letra y colocando una sola línea por bucle en una línea. (1,0)[p%17==16]es +(p%17!=16), o posiblemente incluso p%17!=16.
Jonathan Frech
Además, hay un espacio superfluo en ] for.
Jonathan Frech
Creo que fpdebería ser f.
Jonathan Frech
330 bytes .
Jonathan Frech
2
¿Por qué lo usé ~16? ¡Un poco de ofuscación nunca puede dañar tu golf!
Jonathan Frech
2

Rubí 288

->k{w=17
r=[z=?++?-*w+?+]
(0...w*9).each_slice(w).map{|o|r<<?|+o.map{|x|c=76
q=0
k.split(?:).flat_map{|b|(0..7).map{|i|b.to_i(16)[i]}}.each_slice(2){|h,v|v<1?(c>w&&c-=w):c<w*8&&c+=w
c+=h<1?c%w>0?-1:0:c%w<16?1:0
c==x&&q+=1}
x==76?'S':c==x ?'E':' .o+=*BOX@%&#/^'[q]}.join+?|}
(r+[z]).join'
'}

Pruébelo en línea: http://ideone.com/QOHAnM

La versión legible (la que comencé a jugar al golf) está aquí: http://ideone.com/XR64km

Cristian Lupascu
fuente
2

C - 488

Debe haber una manera de hacer esto más pequeño ...

#include<stdio.h>
#define H ++p;h[i]|=(*p-(*p>58?87:48))<<
#define B ((h[j]>>n*2)&3)
#define L puts("+-----------------+")
#define F(m,s)for(m=0;m<s;m++)
int h[16],m[17][9],i,j,n,x=8,y=4;main(w,v)char**v;{char*p=v[1]-1,c[17]={32,46,111,43,61,42,66,79,88,64,37,38,35,47,94,83,69};for(;*p;p++,i++){H 4;H 0;}F(j,16)F(n,4){if(B&1)x+=!(x==16);else x-=!(x==0);if(B&2)y+=!(y==8);else y-=!(y==0);m[x][y]++;}m[8][4]=15;m[x][y]=16;L;F(i,9){printf("|");F(j,17)printf("%c",c[m[j][i]]);puts("|");}L;}
Jerry Jeremiah
fuente
0

Óxido - 509 bytes

fn b(s:&str)->String{let(mut v,mut b)=([[0;11];20],[9,5]);v[19]=[19;11];for i in 0..16{let mut c=usize::from_str_radix(&s[i*3..i*3+2],16).unwrap();for k in 0..4{for j in 0..2{v[j*18][i%9+1]=18;v[i+k][j*10]=[17,3][(i+k+17)%18/17];b[j]=match(if c&(j+1)==j+1{b[j]+1}else{b[j]-1},j,){(0,_)=>1,(18,0)=>17,(10,1)=>9,x@_=>x.0 as usize,}}v[b[0]][b[1]]+=1;c>>=2;}}v[9][5]=15;v[b[0]][b[1]]=16;(0..220).fold("\n".to_string(),|s,i|{format!("{}{}",s," .o+=*BOX@%&#/^SE-|\n".chars().nth(v[i%20][i/20] as usize).unwrap())})}

Grande pero ... casi cerca de C. Como es habitual, hay muchos bytes usados ​​debido a la forma en que Rust no convierte automáticamente los tipos entre sí. Pero probablemente también haya margen de mejora ... probablemente podría usar algunas ideas de otras soluciones.

versión sin golf está en el Rust Playground en línea

don brillante
fuente