Compresión de tablero de ajedrez más pequeña

39

Escriba un algoritmo o programa que pueda codificar y decodificar un tablero de ajedrez. El objetivo es hacer la representación más pequeña de un tablero de ajedrez que pueda usarse (una vez decodificado) para determinar todas las posibilidades de movimiento para un jugador en ese turno.

La codificación debe poder mostrar:

  • De quién es el turno.
  • Si el jugador puede enrocarse en cada lado.
  • Si el jugador puede realizar un pase, y si es así, ¿cuál de sus peones?
  • Posiciones de todas las piezas.

Nota importante sobre el enroque: si las blancas mueven a su rey un turno, y luego lo retrocede al siguiente, debe quedar claro que no pueden enrocarse en ningún lado después de eso. Lo mismo ocurriría si movieran su torre izquierda o derecha. Aunque el tablero está visualmente en el mismo estado que hace dos turnos, el estado del juego ha cambiado. Más información aquí: http://en.wikipedia.org/wiki/Chess#Castling

Nota importante sobre en-passant: este también es un movimiento sensible al giro. Lea las reglas para más información. http://en.wikipedia.org/wiki/Chess#En_passant

Determine la entrada y salida según sea necesario. ¡Grandes apoyos para quien pueda comprimirlo más!

Su puntaje se determina en el peor de los casos: tamaño máximo posible en bits. Asegúrese de mostrar cómo calculó ese número y lo que representó. ¡Dispara por el peor de los casos!

Agua de Seltz
fuente
¿Qué quieres decir con "bit a bit"?
Peter Taylor
¿Es este el código más pequeño o el más comprimido? La mayoría comprimida es más interesante.
Justin
Perdón por no aclarar. Bitwise en el sentido de que solo puede comprimirlo si comienza a representarlo como bits, lo que requerirá una operación bit a bit. Mal uso de mi parte. También el código más comprimido, no el más pequeño.
Seltzer
2
@GeekWithALife Sí, es posible tener 18 reinas en el tablero al mismo tiempo. Siga este enlace y haga clic en el botón de reproducción para ver un ejemplo.
aprensivo ossifrage
1
@AJMansfield, eso podría ser útil para tableros con aproximadamente 28 hombres, pero calculo que 117 bits es suficiente para tableros con los 32 hombres, que es aproximadamente 50 bits menos que el objetivo. La complicación es que una vez que desciendes por debajo de 32 hombres, la promoción puede dar a un jugador más obispos.
Peter Taylor

Respuestas:

27

Mín .: 12 bits
Máx .:
Promedio:

Anoche pensé que posiblemente podría hacerlo aún más pequeño.

x   Colour to play next (0 -> Black, 1-> White)
1   Only King left?

00000 Position of White King (0 -> A1 ... 63 -> H8)
00000 Position of Black King

01 00000 11111  WK:A1, BK:H2 (Black to play)
11 00000 11111  WK:A1, BK:H2 (White to play)

¡El resultado es un tamaño impresionante de 12 bits !

Entonces, ¿qué pasa con K +1 otro tipo de pieza?

x
 0
   0
     000  +Pawn
     001  +Rook   
     010  +Knight
     011  +Bishop
     100  +Queen

Hay 2 posibles arreglos del subárbol.

   /\      /\
  +  K    K  +

Ambas dan como resultado los mismos tamaños de bits para todas las piezas. Por lo tanto, no importa cuál usemos, elegiré el primero.

x
 0
  0
   000
      1011001110000000000000000000000000000000000000000000000000000000000000
(+ 000) En-Passant (if >= 2 pawn & pawn in en-passant positions)
(+ 00 ) Castlings  (if >= 1 rook)
Min: 75 bit
Max: 109 bits

Así que en King +2 otros tipos de piezas

x
 0
  1
   PRBNQ
   00011  +N +Q
   00101  +B +Q
   00110  +B +N
   01001  +R +Q
   01010  +R +N
   01100  +R +B
   10001  +P +Q
   10010  +P +N
   10100  +P +B
   11000  +P +R

Hay 5 posibles subárboles (usaré 1 y 2 para indicar cuál de las piezas).

   /\          /\       /\         /\          /\
  /  \        /  \     /  \       /  \        /  \
 K   /\      /\   2   /\   \     1   /\      /\   \
    1  2    K  1     K  2   1       K  2    1  2   K

Por lo tanto, necesitaremos 3 bits para codificar qué subárbol usar.

x
 0
  1
   PRBNQ
         000  Sub Tree used

Min:= 11 = Header 
       6 = 2 * 3
       4 = 1 * 4
       4 = 1 * 4
      60 = 60    Empty
      --
      85 bits

Max:=  11 = Header
        4 =  2 * 4 Kings
       48 = 16 * 3 Pawns
       12 =  4 * 3 Rook
       42 = 42 * 1 Empty
        3 =  1 * 3 En-Passant
        2 =  1 * 2 Castlings
      ---
      122 bits

Sigo haciendo el análisis para más piezas

+3 Otro

x
 0
  1
   PRBNQ
         0000  Sub Tree used (of 14 possible)

+4 Otro

x
 0
  1
   PRBNQ
         000000  Sub Tree used (of 42 possible)

+5 Otro

x
 0
  1
   PRBNQ
         0000000  Sub Tree used (of 132 possible)
 (+000)
 (+00)

Max: 208?


¿Es posible codificar todos estos subárboles en 9 bits?

Si sumamos todos los subárboles posibles, obtenemos 392 subárboles posibles.

 1  0
 2  2
 3  5
 4  14
 5  42
 6  132
    ---
    392  <= 2^9

Usar ID de frecuencia

Desde allí 164603 frecuencias de piezas únicas .

Log2( 164603) = 17.3286110452
             ~ 18 bits

0
 0000 0000 0000 0000 00  Freq ID

(+000) (+00) Enroque

Máx .: = 204 bits


rev 3

Mín .: 82 Máx .: 199 Promedio: 160

Finalmente me puse a hacer un análisis para encontrar el tamaño máximo de bit. Con codificación huffman óptima para cada una de las frecuencias de piezas únicas .

               0   Player
              00  Castling
               0  En-Passant Possible
            ?000  En-Passant column (include if En-Passant Possible = 1
  0000 0000 0000  Tree Encoding ID
[Board Encoding]  Between 66 .. 180 bits 

Tenga en cuenta que este es el peor tamaño posible, que la columna En-Passant muerde si el número de peones es mayor que uno. Independientemente de los colores y la posición de esos peones, existe la posibilidad de que algunas tablas sean 3 bits más pequeñas.

Además, solo hay 144 tamaños diferentes (el peor de los casos) para el tamaño del tablero.


75 - 216 bits (v2) v1 El tamaño mínimo es de 98 bits (12.25 bytes), solo los dos reyes en el tablero.

El tamaño máximo es de solo 216 bits (27 bytes). En el caso improbable: -

  9 x Queens
  1 x King
  2 x Rooks
  2 x Knights
  2 x Bishops
on each side.

En promedio, el tamaño será de alrededor de 157 bits (19.625 bytes).

Piezas

Para codificar el tablero, estoy usando un esquema de codificación de árbol binario. Un cuadrado vacío es el más frecuente desde cualquier lugar entre 32 y 62 apariciones. Luego están los peones, luego Rooks, Knights, Bishops y los menos frecuentes son Queen y King.

0 - left node
1 - righ node

     /\
    e  \    e:= Empty Square
      B/\W  B:= Black ; W:= White
      /  \
     /    \
    /      \
   /\      /\
  p  \    p  \  p:= Pawn
     /\      /\
    /  \    /  \
   /\  /\  /\  /\
  r  b n \ r b n \  r:= Rook; b:= Bishop; n:= Knight
         /\      /\ 
        q  k    q  k  q:= Queen ; k:= King

La placa de inicio se puede codificar en solo 166 bits (20,75 bytes)

  A     B     C      D      E     F     G     H
-----+-----+-----+------+------+-----+-----+------+
10100 10101 10110 101110 101111 10110 10101 10100 | 8 
  100   100   100    100    100   100   100   100 | 7
    0     0     0      0      0     0     0     0 | 6
    0     0     0      0      0     0     0     0 | 5
    0     0     0      0      0     0     0     0 | 4
    0     0     0      0      0     0     0     0 | 3
  110   110   110    110    110   110   110   110 | 2
11100 11101 11110 111110 111111 11110 11101 11100 | 1

Para indicar quién se mueve, solo se necesita un bit

0-> Black , 1-> White

El enroque puede codificarse en 4 bits.

 B  W
LR LR
00 00

Entonces uso 171 bits (21.375 bytes)

En-Passe se puede codificar en solo 16 bits (2 bytes)

Entonces, en total, eso es 187 bit (23.375 bytes).

Diseño

  bits    Encodes
 0 -  15  En-Passe
16 -  19  Castling
      20  Move 
21 -  23  Unused
24 -> ..  Board

Aún no se ha escrito ningún código.

Observe que 3 de los bits que no se utilizan. Entonces el máximo es 213bits .


Posibles mejoras

1) Se redujo el bloque de encabezado de 24 a 8 bits (con la sugerencia de @Peter Taylor)

0 - 2 En-Passant
    3 Move
4 - 7 Castling
8 ... Board Pieces 

2) encabezado de longitud variable

Un pequeño encabezado fijo de 4 bits

0 0 0 0
| | | |
| | | +-> En-Passant Block Present?
| | | 
| | +---> Pawns on board?
| |
| +-----> Castling still possible?
|                
+-------> Who's move? 0-Black 
                      1-White

Siguiente bloque de bits adicionales (si el enroque aún es posible)

00 00
|| ||
|| |+-> White Castle Right
|| +--> White Castle Left
||
|+----> Black Castle Right
+-----> Black Castle Left

Siguiente bloque de bits adicionales (si hay peones)

000--> En-Passant column Position

Así que ahora tengo un encabezado de longitud variable de 4 a 11 bits


3) Use un esquema de codificación diferente según las piezas que queden en el tablero.

Al cambiar la codificación del árbol dependiendo de qué piezas están en el tablero y su frecuencia.

Una posible codificación para un estado final del juego (sin peones)

        /\            
       e /\           
  Black /  \ White
       /    \
      /      \
     /        \       
    /\        /\
   /  \      /  \     
  /   /\    /   /\
 /\  / /\  /\  / /\   
r b n q k  r b n q k

Que es aproximadamente ~ 4 bits por pieza.

¿Qué tipo de piezas están presentes en el tablero?

RBNQK Permutation
11111 (11111)

La permutación es de longitud variable de 0-5 bits. Si solo queda un tipo de pieza, no lo incluya.

¿Qué permutación de esas piezas usar para el árbol? Este es el factorial del número de piezas en el ejemplo anterior, son 5 piezas, por lo que se pueden codificar 120 permutaciones posibles.

 #    !  bit 
 6  720  10  (If pawn included)
 5  120   6
 4   24   5
 3    6   3
 2    2   1  Don't include as of equal size.
 1    1   0  Don't include as its not needed.

Recuerde que hay bits de adición para los cuadrados vacíos y el color.


Ejemplos

Pongamos un ejemplo de solo QK restante

RBNKQ
00011

  /\
 s  \
    /\
  B/  \W
  /\  /\
q  k q  k

101 100  0 x 60 110 111 ==> 60 + (2 x 6) = 60 + 12 = 72 bits for the board

0000 00011 Header ==> 9 bits

81 bits en total


Vamos a dar un ejemplo de los reyes que quedan

 RBNQK
 00001 

  /\
 s  k
   / \
  B   W

 10 0 0 0 0 0 0 0   K... ....
  0 0 0 0 0 0 0 0   .... ....
  0 0 0 0 0 0 0 0   .... ....
  0 0 0 0 0 0 0 0   .... ....
  0 0 0 0 0 0 0 0   .... ....
  0 0 0 0 0 0 0 0   .... ....
  0 0 0 0 0 0 0 0   .... ....
  0 0 0 0 0 0 0 11  .... ...k

Poner todo junto

 header  4   0 0 0 0
 pieces  5   0 0 0 0 1
 perm    0   - - - - - -
  board 66   10 0 0 0 0 0 0 0
              0 0 0 0 0 0 0 0
              0 0 0 0 0 0 0 0
              0 0 0 0 0 0 0 0
              0 0 0 0 0 0 0 0
              0 0 0 0 0 0 0 0
              0 0 0 0 0 0 0 0
              0 0 0 0 0 0 0 11

Entonces calculo la codificación más pequeña para la placa a 75 bits (9 bits 3 bits)

Aún no se ha calculado cómo este esquema de codificación afecta el tamaño máximo.


Mejora 4

Reduzca el número de bits para enrocar a solo 2 bits. Solo enroque para el jugador que es el turno.

 0 Castling possible (from header block)
 LR 
 00

Pensando en ello, quizás sea mejor incluir los 2 bits dentro del bloque de encabezado.

Adam Speight
fuente
No necesita 16 bits para pasar. Como máximo, un peón se movió el último turno, por lo que cuatro bits son suficientes (por ejemplo, 1111para "no en passant possible" o la columna como un número binario de lo contrario).
Peter Taylor
¿Por qué los peones obtienen una mejor posición en un árbol? En el caso común, son más comunes, pero en casos extremos, R / B / N puede aparecer 10 veces.
Ugoren
@PeterTaylor, en realidad 3 bits son suficientes para pasar. Si solo cuenta columnas con un peón negro de 5to rango (suponiendo un movimiento blanco), 8 se vuelve inválido.
ugoren
1
Tenga en cuenta que su peor caso en realidad no es posible. La promoción es imposible sin capturas (se necesita al menos una captura por 2 promociones).
ugoren
2
Nota para codificar 64 posiciones (para rey blanco o negro) necesita 6 bits (2 ** 6 = 64).
lambruscoAcido
17

192 bits (peor caso)

Aquí hay un esquema de almacenamiento muy simple que debería hacer frente a promociones arbitrarias de peones, y nunca requiere más de 64 + 4 × 32 = 192 bits:

  • Los primeros 64 bits almacenan un tablero de bits que dice dónde están las piezas (pero no cuáles son). Es decir, almacenamos un bit para cada cuadrado del tablero de ajedrez (comenzando en el cuadrado a1, luego b1, c1, etc. hasta el cuadrado h8) de modo que un cuadrado vacante esté representado por 0 y un cuadrado ocupado por 1.

  • A continuación, para cada uno de los cuadrados marcados como ocupados en el tablero de bits, almacenamos un mordisco de 4 bits que codifica la pieza en ese cuadrado. El primero de los cuatro bits codifica el color de la pieza (0 = blanco, 1 = negro), mientras que los tres bits restantes codifican el tipo de pieza:

    +-----+-----+-----+-----+
    |Black|   Piece Type    |
    +-----+-----+-----+-----+
       4     3     2     1    Bits
    

    Tipo de pieza

    0 = (normal) peón
    1 = (normal) torre
    2 = caballero
    3 = alfil
    4 = reina
    5 = rey (del jugador que se moverá a continuación)
    6 = rey (del otro jugador)

    Tenga en cuenta las dos codificaciones para el rey, que se utilizan para determinar qué turno de jugador debe mover. (De hecho, dado que siempre hay dos reyes en el tablero, lo que permite cuatro combinaciones de los códigos 5 y 6, podríamos codificar fácilmente un segundo bit de información aquí).

    Black Type Description
    +----+----+--------------------------------+
    |  0 | 5  | White King; White to move next |
    +----+----+--------------------------------+
    |  0 | 6  | White King                     |
    +----+----+--------------------------------+
    |  1 | 5  | Black King; Black to move next |
    +----+----+--------------------------------+
    |  1 | 6  | Black King                     |
    +----+----+--------------------------------+
    

    Para codificar la información adicional necesaria para las reglas al pasar y enrocar, introducimos un tipo de pieza adicional, que denota un peón o una torre, dependiendo de la fila en la que aparece:

    7 (en las filas 1 y 8) = una torre que nunca se ha movido, y cuyo rey tampoco se ha movido nunca, y que por lo tanto es elegible para enrocar
    7 (en las filas 4 y 5) = un peón que acaba de avanzar dos casillas, y por lo tanto, puede ser capturado en passant

Poniendolo todo junto:

     Hex Description
    +---+---------------------------------------------+
    | 0 | White Pawn (normal)                         |
    | 1 | White Rook (has moved)                      |
    | 2 | White Knight                                |
    | 3 | White Bishop                                |
    | 4 | White Queen                                 |
    | 5 | White King; White to move next              |
    | 6 | White King                                  |
    | 7 | White Rook (pre castle) / Pawn (en Passant) |
    | 8 | Black Pawn (normal)                         |
    | 9 | Black Rook (has moved)                      |
    | A | Black Knight                                |
    | B | Black Bishop                                |
    | C | Black Queen                                 |
    | D | Black King; Black to move next              |
    | E | Black King                                  |
    | F | Black Rook (pre castle) / Pawn (en Passant) |
    +---+---------------------------------------------+

El número total de bits necesarios para codificar el estado de la placa es, por lo tanto, 64 + 4 × # de piezas a bordo. Como nunca puede haber más de 32 piezas en el tablero, la longitud máxima de esta codificación es de 192 bits.

Por ejemplo, utilizando la codificación descrita anteriormente, el estado inicial de la placa se codificaría como (espacio en blanco insertado para facilitar la lectura):

1111 1111 1111 1111 0000 0000 0000 0000 0000 0000 0000 0000 1111 1111 1111 1111
0111 0010 0011 0100 0101 0011 0010 0111 0000 0000 0000 0000 0000 0000 0000 0000
1000 1000 1000 1000 1000 1000 1000 1000 1111 1010 1011 1100 1110 1011 1010 1111

o, en hexadecimal:

FFFF 0000 0000 FFFF 7234 5327 0000 0000 8888 8888 FABC EBAF
Ilmari Karonen
fuente
2
"peón que acaba de avanzar dos casillas" y "torre que nunca se movió" podrían compartir el mismo espacio de estado ya que son mutuamente excluyentes dependiendo de la fila en la que se encuentren. El estado libre adicional podría usarse para codificar "rey del color de quien es el turno"; deberías poder deshacerte de la parte colgante de esa manera.
FireFly
También puede decirse que puede guardar un bit almacenando solo 63 bits para el tablero e inferir el último bit a partir del número de hombres codificados. (No me queda claro si esto es trampa o no, porque requiere una codificación externa de la longitud de la secuencia de bits). Y si abandona los estados 6 y 7 para los hombres, necesita codificar hasta 6 ^ 32, lo que requiere 82.7 bits; redondeando a 83 está ahorrando 13 bits al usar los estados 6 y 7, y puede codificar esa misma información en solo 8 bits.
Peter Taylor
Gracias, @FireFly! He implementado tu sugerencia. (La sugerencia de Peter Taylor es aún más eficiente, por supuesto, pero no la he usado hasta ahora porque me gusta la codificación binaria simple del esquema actual. Siempre puedes enviarla como una entrada separada ...)
Ilmari Karonen
De acuerdo, esto es un poco complicado. Pero escúchame. Si solo recibes el golpe de 1 bit en un indicador de turno, puedes reemplazar rey por turno con una pieza que yo llamo peón1. Cambiar peón a peón0. Ahora, siempre que haya un peón (no vulnerable), también obtendrá un poco de información en la siguiente pieza (ya sea un 0 para el peón0 o un 1 para el peón1). Debido a que hay 16 peones, gana 16 bits menos 1 para el indicador de giro. Siempre que haya un peón que sea vulnerable al paso, debe agregar un bit nuevamente después. Pero como debe pasar inmediatamente, sus ganancias mínimas son de 14 bits.
user5957401
También podrías hacer algo similar con algo como los obispos. Suponga que tiene un alfil que no está en su "zona especial" (los 10 puntos en sus esquinas y la fila central en su lado) está marcado como especial. Porque conoces su ubicación, sabes que es un obispo. Ahora tienes dos obispos y podrías dar a cada uno un 0 o 1 en la siguiente pieza. Esto da hasta otros 4 bits, pero el peor de los casos tiene obispos en todas las zonas especiales, y no hay ganancia.
user5957401
14

160 bits peor de los casos

Después de publicar mi respuesta anterior de 22 bytes, comencé a preguntarme si podríamos llegar a 21 bytes. Sin embargo, cuando vi los increíbles 166 bytes de Peter Taylor pensé "Espera, ¡parece que cinco palabras de 32 bits podrían ser posibles!"

Entonces, después de pensarlo mucho, se me ocurrió esto: 159.91936391 bytes (¡un ajuste bastante ajustado!) Este nivel de compresión necesitaría un programa bastante complicado, pero he pensado cómo hacerlo funcionar en un tiempo razonable.

Esta será una publicación larga, así que tengan paciencia conmigo, publicaré lo que pueda hoy y agregaré algunos bits de código pronto.

Entonces, aquí está cómo hacerlo:

En Passant y castling codificados por posiciones ilegales (0 bits)

De paso

Como se mencionó en otras respuestas, hay un máximo de 5 casillas posibles en las que puede colocarse un peón vulnerable al paso. Estas son las casillas al lado de los peones del jugador cuyo turno es.

Para codificar esto, el peón vulnerable a passant se intercambia con lo que esté en uno de los cuadrados en la primera o última fila. Esto puede ser un hombre o un cuadrado vacío. Esto produce una posición ilegal, ya que los peones no pueden estar en estas filas. El decodificador debe devolver el peón a su posición correcta, extrayendo la información pasante.

Para que esto no interfiera con la codificación del enroque, es importante que los cuadrados en los que se encuentran los reyes al comienzo del juego no se alteren, y que el procedimiento de codificación pasivo no coloque a los reyes uno al lado del otro, lo cual sería una posición de rey ilegal. Para satisfacer el segundo de estos puntos, el codificador tiene dos opciones en cuanto a qué casilla intercambia el peón al pasar. El primer cuadrado de elección para cada uno de los 5 peones son A8, B8, C8, G8, H8. Segunda opción: A1, B1, C1, G1, H1.

Enroque

Un rey al que se le permite castillo está, por definición, todavía en su casilla inicial. Con el rey blanco en su casilla inicial, hay un total de 63 casillas donde el rey negro puede pararse, 58 de las cuales son legales (no se le permite moverse justo al lado del rey blanco porque se pondría a sí mismo bajo control). Si al rey blanco se le permite enrocarse, se le permite hacerlo con su torre izquierda, su torre derecha o ambas. Por lo tanto, hay 3x58 = 174 posibilidades en las que el rey blanco puede enrolar, otras 174 en las que el rey negro puede enrutar, y otras 3x3 = 9 en las que ambos pueden enloquecer, un total de 357.

Hay 420 arreglos ilegales de los dos reyes donde están en casillas adyacentes: 3x4 = 12 cuando el rey blanco está en la esquina, 5x24 = 120 cuando está en el borde y 8x36 = 288 cuando está en otra casilla. Por lo tanto, hay suficientes posiciones ilegales para codificar todas las posibilidades posibles de enroque.

Si al menos un rey tiene permiso para castillo, el codificador buscaría los datos de enroque y los datos posicionales de aquellos reyes a los que no se les permite castillo en una tabla (o, alternativamente, usar un algoritmo que no especificaré aquí) y producir un ilegal posición de los dos reyes. Luego intercambiaría a los reyes con lo que sucediera en estas casillas.

Es importante que esto se codifique después y se decodifique antes del paso, de lo contrario, existen algunas posibles interferencias.

Comparación

¡Hasta ahora no he usado pedacitos! Mirando la respuesta de Peter, todavía tengo lo siguiente para codificar:

Whose turn is it?                                   1.000 bits
Which squares are occupied by men of which colour? 91.552 bits 
Subtotal                                          *92.552 bits* 
For the two colours, which men and which order?   *68.613 bits* 
GRAND TOTAL                                       161.165 bits

Esto es para el peor caso de 29 hombres (vea la respuesta de Peter). A continuación, mostraré cómo realizo una mejora marginal (al menos para el caso de 29 hombres) en los dos puntos marcados en **.

¿Qué casillas están ocupadas / de quién es el turno?

La manera fácil de codificar qué cuadrados están ocupados es con una cuadrícula de 64 bits. Esto también nos dice cuántos cuadrados están ocupados. Sin embargo, es un poco derrochador porque no es posible que haya más de 32 casillas ocupadas. Mi solución es usar 1's para codificar los cuadrados ocupados cuando es el turno de White y 0's para codificar los cuadrados ocupados cuando es el turno de Black. Ahora se utilizan todas las combinaciones y no hay desperdicio.

Por lo tanto, ahorramos un poco para almacenar el turno: menos de 32 1's, es el turno de las blancas, más de 32 1's, es el turno de las negras. El único caso ambiguo es cuando todos los hombres están en el tablero y hay 32 1 y 32 0. Por lo tanto, se necesita un bit extra solo para este caso. Como no puede haber promociones hasta que se haya producido una captura, este bit adicional no afecta el peor de los casos en general (que ocurre con 3 hombres capturados y 29 restantes).

Color de los hombres que ocupan los cuadrados.

Sabemos por lo anterior cuántos hombres hay. El siguiente extracto del triángulo de Pascal indica cuántas posibilidades hay para las diferentes distribuciones de blanco y negro. Por ejemplo, para 3 hombres, las posibilidades son: 3 hombres negros (1 permutación) 2 negros, 1 blanco, (3 permutaciones), 1 negro, 2 blancos (3 permutaciones), 3 blancos (1 permutación). El total es 2 3 = 8. En general, para el menor número de hombres hay 2 n posibilidades. Sin embargo, todas las posibilidades de negro y blanco son ilegales (al menos el rey de cada lado debe estar en el tablero), por lo que el número real de permutaciones legales es 2 n -2 (ignore los 1 en el triángulo de Pascal).

Para más de 16 hombres en total, existe una restricción adicional en el sentido de que no puede haber más de 16 hombres de cada color en el tablero. Por lo tanto, cuando los 32 hombres están en el tablero, debe haber 16 de cada uno y el número total de posibilidades es 601080390, que es bastante menor que 2 32 .

1   1    1    1      1     1      1       1       1        1        1         1         1         1          1          1          1 
1   2    3    4     5      6      7       8       9       10       11        12        13        14         15         16         17
1   3    6   10    15     21     28      36      45       55       66        78        91       105        120        136        153
1   4   10   20    35     56     84     120     165      220      286       364       455       560        680        816        969
1   5   15   35    70    126    210     330     495      715     1001      1365      1820      2380       3060       3876       4845
1   6   21   56   126    252    462     792    1287     2002     3003      4368      6188      8568      11628      15504      20349
1   7   28   84   210    462    924    1716    3003     5005     8008     12376     18564     27132      38760      54264      74613
1   8   36  120   330    792   1716    3432    6435    11440    19448     31824     50388     77520     116280     170544     245157
1   9   45  165   495   1287   3003    6435   12870    24310    43758     75582    125970    203490     319770     490314     735471
1  10   55  220   715   2002   5005   11440   24310    48620    92378    167960    293930    497420     817190    1307504    2042975
1  11   66  286  1001   3003   8008   19448   43758    92378   184756    352716    646646   1144066    1961256    3268760    5311735
1  12   78  364  1365   4368  12376   31824   75582   167960   352716    705432   1352078   2496144    4457400    7726160   13037895
1  13   91  455  1820   6188  18564   50388  125970   293930   646646   1352078   2704156   5200300    9657700   17383860   30421755
1  14  105  560  2380   8568  27132   77520  203490   497420  1144066   2496144   5200300  10400600   20058300   37442160   67863915
1  15  120  680  3060  11628  38760  116280  319770   817190  1961256   4457400   9657700  20058300   40116600   77558760  145422675
1  16  136  816  3876  15504  54264  170544  490314  1307504  3268760   7726160  17383860  37442160   77558760  155117520  300540195
1  17  153  969  4845  20349  74613  245157  735471  2042975  5311735  13037895  30421755  67863915  145422675  300540195  601080390

El número de posibilidades se puede encontrar sumando las "filas" de este extracto del triángulo de pascales (con lo cual me refiero a las diagonales NE-SW de la tabla, porque giré el triángulo 45 grados en sentido contrario a las agujas del reloj para una presentación conveniente). para codificar el turno, los cuadrados ocupados y el color de los hombres son, por lo tanto, los siguientes:

Hasta 25 hombres: un poco menos de 64+ (número de hombres)
Para más de 25 hombres:

men permutations  bits required  occupied sq+turn   
    of colours                   (bits required)  total bits
26   55791790     25.7335495      64              89.7335495
27  100960110     26.58921015     64              90.58921015
28  175844430     27.3897244      64              91.3897244
29  290845350     28.115677       64              92.115677   
30  445962870     28.73234836     64              92.73234836
31  601080390     29.16298271     64              93.16298271
32  601080390     29.16298271     65              94.16298271

Para los dos colores, ¿qué hombres y en qué orden?

Según las respuestas anteriores, no se pueden promover peones hasta que se haya producido una captura, porque cada peón está bloqueado por un peón del color opuesto en la misma columna. La respuesta de Peter consideró (como límite superior) que cada captura podría conducir a una promoción para el lado que se está capturando y dos para la captura del lado. Sin embargo, podemos dividir esto en varios casos:

  1. El peón negro captura el peón blanco: ahora el peón capturador es libre de promocionar ya que ahora está en una columna diferente. Su colega en la misma columna también puede promocionar. El peón negro en la columna original del peón blanco también puede promover. Este es el único caso que permite 3 promociones.

  2. El peón negro pasa el peón blanco en la columna adyacente y luego captura la pieza blanca (que no sea el peón) detrás. Esto permite que el peón de captura y el peón blanco que estaba en la columna original promocionen. Una promoción para cada lado.

  3. El peón blanco es capturado por pieza (que no sea el peón). Esto normalmente permitiría una promoción solo para negros. La única excepción es cuando libera una formación de peón bloqueada que ya fue causada por varias capturas que movían peones a la misma columna.

Entonces, como caso base, podemos considerar que cada captura permite una promoción cada una para ambos lados. En el caso de que el hombre capturado sea un peón, puede haber una promoción adicional para el lado de captura.

He escrito un programa similar al de Peter. Es algo más crudo, pero tiene una adición importante: puede calcular el número de permutaciones posibles cuando un jugador comienza con menos de los 8 peones normales. Aquí hay algunos datos producidos por el programa:

Max promotions   0            1            2             3             4              5 
8 PAWNS 
13 men    18725850    146911050    567991710    1373480394    2297173164     2902775304
14 men    36756720    339459120   1555313760    4501448952    9021804792    13325103792
15 men    60810750    660810150   3555401850   12144582450   28834205400    50030580600
16 men    64864800    843242400   5383778400   21810428640   61514893440    1.26476E+11
7 PAWNS                         
13 men    17760600    141003720    546949260    1321302840    2200401060     2761730400
14 men    30270240    287567280   1331890560    3852728880    7641553920    11068817760
15 men    32432400    372972600   2075673600    7209001800   17135118000    29315286000
6PAWNS                          
13 men    14054040    114594480    447026580    1069488420    1739577840     2113185360
14 men    15135120    151351200    718918200    2087805720    4073028960     5697051360                         
5 PAWNS                         
13 men     6486480     55135080    217297080     510630120     794233440      910235040

Podemos ver que para un caso como 8 peones, 15 hombres, 0 promociones, el número de permutaciones es solo ligeramente menor que para 8 peones, 16 hombres, 0 promociones. Sin embargo, si consideramos un caso como 7 peones, 15 hombres, 0 promociones (que es lo mismo que considerar que el hombre capturado fue definitivamente un peón) obtenemos aproximadamente la mitad del número de permutaciones.

Entonces, para el caso en que las negras tienen 16 hombres y las blancas tienen 15 hombres, podemos considerar una estimación del límite superior de 2 promociones para las negras y una promoción para las blancas:

5383778400 x 660810150 = 3.55766E+18 possibilities

Sin embargo, podemos hacerlo mejor si procedemos de la siguiente manera.

A. Considere una promoción para cada uno en blanco y negro, suponiendo que el hombre que White ha perdido podría ser de cualquier tipo:

843242400 x 660810150 = 5.57223E+17 possibilities

B. Considere las posibilidades adicionales para las negras si tiene dos promociones, multiplicadas solo por las posibilidades para las blancas en las que ha perdido un peón.

(5383778400-843242400) x 372972600 = 1.6935 E+18 possibilities.

Sumando estos dos juntos obtenemos 2.25072E + 18, que es un número menor que 3.55766E + 18. A continuación se enumeran todas las posibilidades para hasta 3 capturas (quedan 29 hombres).

(Promotions, Pawns lost) possibilities

BLACK 16 MEN, WHITE 15 MEN. ESTIMATE   3.55766E+18 = 2^61.62563249
(1,0)   843242400 x (1,0)  660810150 = 5.57223E+17
(2,0)  4540536000 x (1,1)  372972600 = 1.6935 E+18
                               TOTAL   2.25072E+18 = 2^60.96509144


BLACK 16 MEN, WHITE 14 MEN. ESTIMATE   9.5675 E+19 = 2^66.3747752
(2,0)  5383778400 x (2,0) 1555313760 = 8.37346E+18
(3,0) 16426650240 x (2,1) 1331890560 = 2.18785E+19
(4,0) 39704464800 x (2,2)  718918200 = 2.85443E+19
                               TOTAL   5.87962E+19 = 2^65.67235739


BLACK 16 MEN, WHITE 13 MEN. ESTIMATE   2.69447E+20 = 2^67.86856193
(3,0) 21810428640 x (3,0) 1373480394 = 2.99562E+19
(4,0) 39704464800 x (3,1) 1321302840 = 5.24616E+19
(5,0) 64960896000 x (3,2) 1069488420 = 6.94749E+19
(6,0) 69702272640 x (3,3)  510630120 = 3.55921E+19
                               TOTAL   1.87485E+20 = 2^67.34533572


BLACK 15 MEN, WHITE 15 MEN. ESTIMATE   1.47491E+20 = 2^66.99918768
(2,0)  3555401850 x (2,0) 3555401850 = 1.26409E+19
(2,1)  2075673600 x (3,0) 8589180600 = 1.78283E+19
(3,0)  8589180600 x (2,1) 2075673600 = 1.78283E+19
(3,1)  5133328200 x (3,1) 5133328200 = 2.63511E+19
                  TOTAL BOTH COLUMNS   7.46486E+19 = 2^66.01674923


BLACK 15 MEN, WHITE 14 MEN. ESTIMATE   4.51366E+20 = 2^68.61286007      
(3,0) 12144582450 x (3,0) 4501448952 = 5.46682E+19
(3,1)  7209001800 x (4,0) 4520355840 = 3.25873E+19
(4,0) 16689622950 x (3,1) 3852728880 = 6.43006E+19
(4,1)  9926116200 x (4,1) 3788825040 = 3.76083E+19
(5,0) 21196375200 x (3,2) 2087805720 = 4.42539E+19
(5,1) 12180168000 x (4,2) 1985223240 = 2.41804E+19
                  TOTAL BOTH COLUMNS   2.57599E+20 = 2^67.80368692

Entonces, para el peor caso de un lado con 15 hombres y el otro con 14 hombres, necesitamos 67.804 bits.

Agregando esto a los 92.116 bits requeridos para especificar qué cuadrados y qué color, obtenemos un total de 67.804 + 92.116 = 159.92 bits.

Level River St
fuente
1
Muchas gracias a @Einacio por cambiar mis comas decimales a puntos decimales. Hice muchas de mis tablas en Excel en una computadora en español, y publicar esto fue un gran trabajo, por lo que solucionar esto fue algo que dejé para más tarde. Como digo, aún no he terminado esta publicación, agregaré mi programa de conteo de permutación y algunos fragmentos de código sobre codificación / decodificación cuando tenga tiempo. PD. No tenía idea de que tanta gente estaba leyendo esto :-)
Level River St
al final lograste tomar bytes en lugar de bits, que es lo que querías decir, eso podría causar cierta confusión a los lectores
masterX244
13

177 bits peor caso

Este algoritmo, aunque no es simple, da el peor de los casos de 177 bits (184b = 23B en la práctica), el mejor de los casos en 13b (16b = 2B) cuando solo quedan 2 reyes.

Bit     Description
  1     Turn (0=white 1=black)
  2-  7 White king position (2-4=letter, 5-7=number)
  8- 13 Black king position (8-10=letter, 11-13=number)
 14- 75 Which squares contain pieces (skipping the 2 king squares, so only 62)
        Ordered a1-h1,a2-h2,(...)
 76-105 Which color owns the square with their piece (0=white, 1=black)
        If there's LESS than 30 pieces (apart from kings), this area is
        smaller
106-end Square data

Square data has the following system:
Every square gets assigned a number which determines piece. Number is:
0 Queen
1 Rook
2 Bishop
3 Knight
4 Pawn OR allowed-castle rook depending on square
5 Pawn subject to potential enpassant

The first bits (max 13) is the potential enpassant slots from A-H, determined
from data of 1 + 14-105 for which of the squares has a piece, and which color
owns the piece and whose turn it is. For example, if turn is White (bit 1 is
0), all pieces on row 5 which is Black owned (determined from 14-105 metadata)
and has at least 1 adjacant (on the same row) square owned by White, is
explained in A-H order. A base 6 number is used which is converted to binary
for the storage. On reading, it's converted and read A-H according to the
numbers above (4 is obviously pawn in this case).
The second amount of bits takes care of the 1st and 8th row (not corners!)
in b1-g1,b8-g8. These only take up 2 bits since 4 or 5 is never needed
(pawn on 1st or 8th is invalid).
The third amount of bits takes care of the rest of the board, in the following
order: a1,h1,a2-h2,a3-h3,a4-h4,a5-h5,a6-h6,a7-h7,a8,h8 (skipping the
"enpassant" slots), in base 5 (since piece ID 0-4 are the only used) converted
to binary.

Best case: 13 bits (bit 1 for turn, bit 2-12 for kings)
Worst case: 177 bits
* 32 pieces with kings
* 5 viable enpassant pawns
* No pieces at 1st or 8th row (except if kings+rooks are at initial posions
whether or not they can castle)
In this case, the space as following:
  1   bit   turn
+ 12  bits  king positions
+ 62  bits  which squares have pieces
+ 30  bits  color of pieces
+ 13  bits  enpassant area
+ 0   bits  initial rows area
+ 59  bits  the rest of the area
= 177 bits  total

Potential optimizations but not really worth it IMO:
* Decrease average by make corners 2 bits as well if kings aren't at e1/e8
* Alter reading order to read b1-g1,b8-g8 last - decreases worst case to
  176 bits if the "which squares have pieces" area is cut off if 30 existing
  pieces has been defined already. Would actually save 8 bits on file but meh
FIQ
fuente
Muy agradable. Puede hacerlo aún más eficiente reemplazando los bits 14-105 (92 bits) con una codificación basada en coeficientes multinomiales. sum_{i=0}^{15} sum_{j=0}^{15} 62! / (i! j! (62-i-j)!) < 2^87.45.
Peter Taylor
Lo único que cambiaría es crear una versión bastante más simplificada para el área de paso. Por ejemplo: si codifica las 30 piezas en la base 5, y hay un máximo de 5 posiciones de paso, entonces puede tener 5 ^ 31 <2 ^ 72. Lo mismo que si los dividiera en enpassant (13) y no enpassant (59), pero sin la complejidad adicional.
Alin Stoian
Hacer eso realmente usaría 1 bit extra. La razón es que puede haber (en el peor de los casos) 5 posibilidades pasajeras, pero todavía necesito declarar la posibilidad de "no pasante", es decir, un sexto estado. El 1 bit adicional en este caso iría a declarar posible o no el paso (y con este enfoque también podría usar un enfoque aún más simple con la codificación de las 30 piezas omitiendo el bloque de paso, y usar 3 bits por separado para la verificación de paso, lo que sería también conducen a un uso de +1 bit). La siguiente quinta fila permitiría 5 posibles pasadas (turno de White): BWBBWBBW
FIQ
sí tienes razón.
Alin Stoian
7

166 bits

  • 1 bit: ¿de quién es el turno?
  • 2bits: ¿qué opciones de enroque están abiertas? (Nota: al leer detenidamente la pregunta, solo es necesario registrar las opciones de enroque para el jugador cuyo turno es).
  • lg 6 ~= 2.585bits: ¿qué opciones pasantes están abiertas? (Ver mi otra respuesta)
  • lg sum_{i=1}^{16} sum_{j=1}^{16} 64! / (i! j! (64-i-j)! = lg 3629590441720924477681996172 ~= 91.552 bits: ¿qué cuadrados están ocupados por hombres de qué color?
  • En el peor de los casos, lg 451366131803622235200 ~= 68.613para indicar qué hombres y en qué orden (ver más abajo)

Usando la codificación aritmética (ya que en cada paso estamos aplicando una distribución uniforme) podemos lograr ceil(3 + 2.585 + 91.552 + 68.613) = 166bits.

La codificación para los hombres: dado que sabemos cuántos hombres de un color dado hay, podemos enumerar fácilmente todas las posibles distribuciones / conjuntos múltiples de hombres (por ejemplo, con 5 hombres podríamos tener un Rey, una Reina, dos Rooks y un Peón) y luego podemos considerar todas las permutaciones posibles de cada distribución.

Sin embargo, podemos hacerlo aún mejor teniendo en cuenta las interdependencias. Solo estoy haciendo esto en un nivel muy básico: ¿cuántas promociones posibles? Un peón solo se puede "pasar" y puede promocionar de tres maneras: captura y, por lo tanto, se mueve a una columna diferente; o su peón opuesto captura y se mueve a una columna diferente; o su peón contrario es capturado. Por lo tanto, una captura para blanco crea potencialmente dos peones pasados ​​para blanco y uno para negro.

Podemos construir una tabla parcial de los límites superiores en las promociones:

(Max white promos, max black promos):

           White men
           16      15      14      13
Black men
       16  (0, 0)  (1, 2)  (2, 4)  (3, 6)
       15  (2, 1)  (3, 3)  (4, 5)  (5, 7)
       14  (4, 2)  (5, 4)  (6, 6)  (7, 8)
       13  (6, 3)  (7, 5)  (8, 7)  (8, 8)

También podemos calcular el número de permutaciones dado que un jugador tiene Nhombres y no más que Ppeones promovidos:

Num of permutations (cumulative):
    max promotions: 0              1              2              3              4              5              6              7              8
 1 men              1              1              1              1              1              1              1              1              1
 2 men             10             10             10             10             10             10             10             10             10
 3 men             72             75             75             75             75             75             75             75             75
 4 men            436            496            500            500            500            500            500            500            500
 5 men           2305           3025           3120           3125           3125           3125           3125           3125           3125
 6 men          10746          17106          18606          18744          18750          18750          18750          18750          18750
 7 men          44170          88795         106260         109179         109368         109375         109375         109375         109375
 8 men         159832         415360         575240         619200         624744         624992         625000         625000         625000
 9 men         509841        1721961        2884815        3398769        3504735        3515301        3515616        3515625        3515625
10 men        1447200        6258240       13063080       17697780       19260180       19510320       19530840       19531230       19531240
11 men        3706065       20021265       52183395       85007571      102173181      106786581      107369592      107409918      107410281
12 men        8678340       57101220      183088620      364510476      509818716      570620556      584017632      585352152      585430164
13 men       18725850      146911050      567991710     1373480394     2297173164     2902775304     3107861328     3143928216     3146014014
14 men       36756720      339459120     1555313760     4501448952     9021804792    13325103792    15664512864    16283899632    16360920576
15 men       60810750      660810150     3555401850    12144582450    28834205400    50030580600    66655789200    73588394880    74576231730
16 men       64864800      843242400     5383778400    21810428640    61514893440   126475789440   196178062080   240747386880   253686232800

Combinando los dos, podemos obtener la cantidad de bits necesarios para especificar ambas permutaciones dada la cantidad de hombres en ambos lados:

           White men
           16      15      14      13      <13
Black men
       16  51.902  61.626  66.375  67.868  <=67.009
       15  --      67.000  68.613  67.534  <=65.243
       14  --      --      67.734  65.480  <=63.055
       13  --      --      --      63.102  <=60.676

Si no está en esta sección de la tabla, podemos suponer que ambas partes tienen hasta 8 promociones y todavía lo estamos haciendo mejor que en el peor de los casos, que es 68.613 bits cuando uno tiene 14 hombres y el otro tiene 15 hombres.

Tenga en cuenta que esto aún está lejos de ser una representación perfecta, ya que permite muchas posiciones ilegales.

Código para calcular la tabla de permutación:

import java.util.*;

public class ChessCombinatorics {
    public static void main(String[] args) {
        long[] f = new long[17];
        f[0] = 1;
        for (int i = 1; i < 17; i++) f[i] = i * f[i-1];

        // Indexed by num promotions, then total num men.
        long[][] distribs = new long[9][17];
        long[][] perms = new long[9][17];

        for (int promotedPawns = 0; promotedPawns < 9; promotedPawns++) {
            Map<Integer, Map<String, Long>> numCases = new HashMap<Integer, Map<String, Long>>();
            for (int i = 1; i < 17; i++) numCases.put(i, new HashMap<String, Long>());

            for (int extraQ = 0; extraQ <= promotedPawns; extraQ++) {
                for (int extraR = 0; extraR + extraQ <= promotedPawns; extraR++) {
                    for (int extraN = 0; extraN + extraR + extraQ <= promotedPawns; extraN++) {
                        int extraB = promotedPawns - extraN - extraR - extraQ;
                        int unpromotedPawns = 8 - promotedPawns;

                        // Promoted pawns should only count towards their new type if the existing ones are alive.
                        // Otherwise we double-count some cases.
                        int minQ, maxQ, minR, maxR, minN, maxN, minB, maxB;
                        if (extraQ == 0) {minQ = 0; maxQ = 1;} else {minQ = maxQ = 1 + extraQ;}
                        if (extraR == 0) {minR = 0; maxR = 2;} else {minR = maxR = 2 + extraR;}
                        if (extraN == 0) {minN = 0; maxN = 2;} else {minN = maxN = 2 + extraN;}
                        if (extraB == 0) {minB = 0; maxB = 2;} else {minB = maxB = 2 + extraB;}

                        for (int numQ = minQ; numQ <= maxQ; numQ++) {
                            for (int numR = minR; numR <= maxR; numR++) {
                                for (int numN = minN; numN <= maxN; numN++) {
                                    for (int numB = minB; numB <= maxB; numB++) {
                                        for (int numP = 0; numP <= unpromotedPawns; numP++) {
                                            // The number of possibilities at these values is (numK + numQ + numR + numN + numB + numP)! / (numK! numQ! numR! numN! numB! numP!)
                                            numCases.get(1+numQ+numR+numN+numB+numP).put(numQ+","+numR+","+numN+","+numB+","+numP, f[1 + numQ + numR + numN + numB + numP] / f[numQ] / f[numR] / f[numN] / f[numB] / f[numP]);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            for (int numMen = 1; numMen < 17; numMen++) {
                distribs[promotedPawns][numMen] = numCases.get(numMen).size();
                if (distribs[promotedPawns][numMen] > 0) {
                    for (Long l : numCases.get(numMen).values()) perms[promotedPawns][numMen] += l;
                }
            }
        }

        System.out.println("Num of permutations (cumulative):");
        System.out.println("    max promotions: 0              1              2              3              4              5              6              7              8");
        for (int numMen = 1; numMen < 17; numMen++) {
            System.out.print(String.format("%2d men", numMen));
            long cumul = 0;
            for (int promotedPawns = 0; promotedPawns < 9; promotedPawns++) {
                cumul += perms[promotedPawns][numMen];
                System.out.print(String.format("%15d", cumul));
            }
            System.out.println();
        }

        System.out.println("Entropy of permutations:");
        System.out.println("    max promotions: 0              1              2              3              4              5              6              7              8");
        for (int numMen = 1; numMen < 17; numMen++) {
            System.out.print(String.format("%2d men", numMen));
            long cumul = 0;
            for (int promotedPawns = 0; promotedPawns < 9; promotedPawns++) {
                cumul += perms[promotedPawns][numMen];
                System.out.print(String.format("  %6.3f", Math.log(cumul) / Math.log(2)));
            }
            System.out.println();
        }

    }
}
Peter Taylor
fuente
¿Cómo deduces las posiciones de los reyes? Utiliza 15 hombres en su cálculo y no hay bits especiales para las posiciones de rey.
Alin Stoian
@AlinStoian, ¡Uy! Tenía un bucle de salida en <lugar de <=en mi programa. Gracias por mencionarlo. Todavía podría recuperar el puntaje anterior con un revestimiento especial de los 32 hombres que están en el tablero, pero no lo haré en este momento.
Peter Taylor
Datos interesantes El peor caso teórico con 3 hombres capturados
Level River St el
@steveverrill, lo que realmente me gustaría hacer es codificar las posiciones de peón y el número de promociones en un "bloque" y luego las posiciones y los valores de las piezas. Sin embargo, hay al menos 2 ^ 38 posiciones de peón sin tener en cuenta las promociones, y enumerarlas de manera eficiente hasta ahora se me ha escapado.
Peter Taylor
@petertaylor Si solo tienes 16 peones en el tablero, restringidos a 48 cuadrados, tienes 48! / 32! / 8! / 8! = 29019905518636890 posibilidades. ¡Un poco más de 2 ^ 54! De estos, algunos son ilegales, no puedes tener todos los peones de un color en un lado del tablero.
Level River St el
5

178 bits (¡174 en un apuro!) Peor de los casos

Hola, acabo de volver a la codificación, lo que realmente no he hecho desde la universidad. Vi este sitio y pensé que esto parecía interesante. Hice una pequeña comprobación teórica y parece que se necesitan al menos 146 bits para un algoritmo perfecto, probablemente bastantes más (explicaré en los comentarios cuando tenga un momento).

De todos modos, esta es la forma en que estructuro los datos. El concepto básico viene en 178 bits, pero con algo de jiggery pokery puede reducirse a 174 (eso es 21 3/4 bytes). 175 es un poco más fácil de programar, es más legible para los humanos y aún tiene 22 bytes.

A) Posición de ambos reyes: 6 bits cada uno para blanco y negro de 12 BITS

B) De los 62 cuadrados restantes, ¿cuáles están ocupados? Una matriz de 62 BITS

C) ¿De quién es el turno? 1 BIT

TOTAL HASTA AHORA: 75 BITS

D) En Passant. Si es el turno de las blancas de moverse, puede parecer que hasta 5 peones negros podrían ser capturados en Passant. El peón negro debe estar en la fila 5 (de abajo hacia arriba comenzando en cero) y tener un peón blanco al lado. Una situación con el número máximo de capturas posibles se ve así:

BWBBWBBW

Si hubiera 6 peones negros en la fila 5, las blancas solo tendrían 2 cuadrados para pararse y solo podrían amenazar a 4 peones negros, por lo que no es posible tener más de 5 peones negros aparentemente amenazados por En passant al mismo tiempo. Por lo tanto, necesitamos un número del 1 al 5 que indique cuál de los (hasta 5) peones en la fila 5 que tiene un peón hostil (en este caso blanco) junto a él avanzó 2 casillas en el último turno ( o cero si no hay peón en esta situación se movió de esta manera en el último turno).

E) De los hasta 30 cuadrados ocupados (sin incluir reyes), ¿qué contienen?

Hay 10 posibilidades, cada una representada por un número decimal.

El bit menos significativo representa el color.

Por lo tanto, los números pares son blancos, los impares son negros.

Blanco negro

Peón 0/1 (o Torre que se le permite al castillo *)

Caballero 2/3

Obispo 4/5

Torre 6/7

Reina 8/9

* Una torre que se le permite al castillo (y por lo tanto nunca se ha movido de la primera o última fila) está representada por 0 o 1 en lugar de 6 o 7. No se puede confundir con un peón, porque no se pueden encontrar peones en la primera o la última fila.

Esto proporciona un número decimal de hasta 30 dígitos, que podemos multiplicar por 6 y luego agregar el código para En passant. El número resultante se ajustará a 103 bits, que cuando se agrega a los 75 mencionados anteriormente es 103 + 75 = 178 bits . En realidad, si simplemente multiplicamos por 10 en lugar de 6, no importa el número de bits utilizados, y la decodificación es más fácil.

Esto es solo 2 bits más de 22 bytes. Sin embargo, podemos reducirlo a 174 bits, como se explica a continuación.

Si no se ha capturado ninguna pieza, entonces es imposible promover un peón .

La prueba es como sigue. Imagina que las blancas están obsesionadas con promocionar su peón en (por ejemplo) la columna E, desde el comienzo del juego. Hay un peón negro enfrente de este peón que está en el camino. Por lo tanto, para promover este peón, debe ocurrir uno de los siguientes:

1) Se captura el peón negro.

2) El peón negro captura otra pieza y, por lo tanto, se aparta del camino.

3) el peón blanco captura un peón en una columna adyacente, como la columna D.

4) el peón blanco pasa (o pasa) un peón negro en una columna adyacente y luego captura una pieza en esa misma columna adyacente, lo que hace que el peón blanco cambie de columna.

El caso 4 es el más interesante, porque no es solo el peón blanco que comenzó en la columna E el que ahora tiene un camino claro hacia la promoción. El peón negro en la columna que permanece en la columna E también puede promover. Por lo tanto, una sola captura puede despejar el camino para que un peón de cada color se promueva.

De todos modos, el hecho de que ningún peón pueda promocionar hasta que se capture una pieza significa que no tenemos que almacenar la pieza 30. Podemos resolverlo por eliminación (o por sustracción, porque el conjunto completo de códigos de pieza al comienzo del juego siempre suma la misma cantidad = 80). Un punto menor es que debemos asegurarnos de que los cuadrados donde están las torres al comienzo del juego se encuentran los primeros escaneados (porque si fueran los últimos, no sabríamos si la torre podría enrocarse o no). Esto se hace fácilmente escaneando la fila 0 y luego las filas 7 a 1: Para r = Fila de exploración 8 a 1 [r mod 8].

Entonces, la matriz de bits en (B) nos dirá cuántas piezas hay (excluyendo reyes). Si hay un total de 30, ignore la última pieza al codificar, el decodificador resolverá cuál era. Ahora tenemos un número decimal de hasta 29 dígitos, que multiplicamos por 6 y agregamos al código En Passant. El número resultante se comprimirá en 99 bits, dando un total de 99 + 75 = 174 bits.

Como ejemplo, aquí hay una posición real. Las blancas acaban de hacer su primer movimiento (peón del rey avanzado) y es el turno de las negras.

rnbqkbnr
pppppppp


    P

PPPP PPP
RNBQKBNR

A) Posición de los reyes (Blanco / Negro en octal, 12 bits ): 03 73 = 000011 111011

B) ¿Qué cuadrados están ocupados? Comience con la fila cero (fila inferior), luego todas las demás filas de arriba a abajo, omitiendo a los reyes:

1111 111

1111 111
11111111
00000000
00000000
00001000
00000000
11110111 

C) Turno negro: Bit de giro = 1

D) En Passant. No hay peón blanco al lado de un peón negro, por lo tanto, no hay peón que se pueda tomar de pasada (aunque este peón sí avanzó el último movimiento), entonces D = 0.Si, en lugar de considerar solo los peones que tienen un peón hostil junto a ellos, consideramos todos los peones que no tienen piezas amigas al lado de ellos en ambos lados, entonces D sería 1, ya que hay uno de esos peones en esta situación, y esto en particular el peón se movió de hecho en el último turno.

E) Nuevamente, primero la fila inferior, luego todas las demás filas de arriba a abajo, omitiendo a los reyes, y con las cuatro torres no extendidas denominadas 0 o 1 (números normalmente reservados para los peones).

RNBQ BNR =   0248 420
rnbq bnr =   1359 531
pppppppp =   11111111
PPPPPPPP = (0)0000000

El trigésimo dígito (entre paréntesis) se puede descartar.

Aunque no es muy evidente aquí, el peón que las blancas han avanzado está realmente en un extremo de la lista de peones, porque escaneamos fila por fila.

Nuestros datos ahora se ven así, con 29 códigos para el contenido de cuadrados, más el código En Passant:

 (0 discarded) 0000000 11111111 1359531 0248420 (0 en passant)

Es mejor escanear de derecha a izquierda al decodificar y de izquierda a derecha (orden inverso) al codificar. Esto significa que cuando haya menos piezas tendremos un número menor, al tiempo que mantendremos la máxima consistencia (es decir, queremos que el espacio en blanco / ceros sean iniciales, no finales, para permitir la compresión de tablas escasamente ocupadas). Cuando solo tenemos 2 reyes en el tablero, tendremos los 75 bits mencionados anteriormente, más 3 bits para almacenar datos passant = 78 bits en el mejor de los casos. Cada pieza adicional viene en un poco menos de 3.5 bits (2 piezas se pueden almacenar en 7 bits, porque 100 <128).

Existe un problema práctico en el sentido de que un número entero de 99 bits es demasiado grande para caber en una variable entera de 64 bits, lo que significa que muchos lenguajes de programación no lo admiten (no puede convertir simplemente una representación de cadena de 29-30 dígitos número en un número entero.) Como una manera fácil de codificar para 22 bytes, podemos dividir un número de 30 dígitos (códigos de 29 piezas + código pasante) en dos números de 15 dígitos, cada uno de los cuales cabrá en 50 bits cada uno (total de 100 bits además de los 75 mencionados anteriormente, el peor caso es de 175 bits).

Para una compresión máxima, como se indicó anteriormente, 29 dígitos decimales más el código En Passant (6 valores posibles), casi encajarán en 99 bits (para un total de 174 bits) pero sin el soporte del lenguaje para enteros de este tamaño es complicado de programar Puede ser más fácil separar los 29 bits de color y trabajar con los códigos de pieza (5 posibilidades) y el código En passant (6 posibilidades) por separado de los colores (70 bits, casi encaja en una variable de 64 bits).

Level River St
fuente
Buen truco con el último hombre.
Peter Taylor
5

Aquí hay una solución completa, el peor de los casos, 181 bits

El enfoque aquí es un programa simple que puedes entender fácilmente

La entrada es FEN, aquí está la posición de apertura, tiene seis campos (5 y 6 ignorados):

rnbqkbnr / pppppppp / 8/8/8/8 / PPPPPPPP / RNBQKBNR w KQkq - 0 1

El primer campo (colocación de piezas) se analiza

perl -pe 's/\d/"_"x$&/ge;s/\s.*//;s|/||g'

Para producir:

rnbqkbnrpppppppp________________________________PPPPPPPPRNBQKBNR

Campo uno: codifica la ubicación de los reyes (12 bits):

printf("%b",index('k',$_))
printf("%b",index('K',$_))

Campo dos: codificar piezas (hasta 5 bits por pieza):

s/_/0/g     Blank
s/P/100/g   From here, as normal chess meaning
s/p/101/g
s/Q/11000/g
s/q/11001/g
s/R/11010/g
s/r/11011/g
s/B/11100/g
s/b/11101/g
s/N/11110/g
s/n/11111/g
s/K//
s/k//

Campo tres: color activo (1 bit)

s/w/0/
s/b/1/

Campo cuatro: disponibilidad de enroque (4 bits)

m/K/?1:0
m/k/?1:0
m/Q/?1:0
m/q/?1:0
  • FIQ muestra este campo podría eliminarse por completo.

Campo cinco: en passant (cero o 3 bits)

printf("%b",ord($1)-ord("a")) unless m/-/
// The EP's rank is 3 or 6 based on active color, only need to encode file

Ingenuo peor caso 200 bits

  • Colocaciones de dos reyes - 12 bits
  • Tablero
    • QRRBBNN QQQQQQQQ - 75 bits
    • qrrbbnn qqqqqqqq - 75 bits
    • Cuadrados vacíos - 30 bits
  • Color activo - 1 bit
  • Castling - 4 bits
  • En Passant - 3 bits

El peor caso real

Cada jugador no puede promover todos los peones sin capturar otras piezas . Aquí está el efecto de entropía de la captura de piezas:

  • PpR(3 + 3 + 5 = 11 bits) => Qq_(5 + 5 + 1 = 11 bits)
  • PPpp(3 + 3 + 3 + 3 = 12 bits) => QQq_(5 + 5 + 5 + 1 = 16 bits)

Entonces, en realidad, el peor caso es:

  • QRRBBNN QQQQQQQQ - 75 bits
  • qrrbbnn qqqq - 55 bits
  • Cuadrados vacíos - 34 bits

El peor de los casos es promover todas las piezas en lugar de dejar el peón para pasar.

TOTAL CASO PEOR REAL CON CÓDIGO MOSTRADO 12 + 75 + 55 + 34 + 1 + 4 = 181 bits

FIQ muestra dos mejoras a este esquema simple, pero son más difíciles de codificar:

  • Elimine el bit 2 de la codificación de piezas en las filas 1 y 8 ya que los peones no pueden ir allí (ahorro de hasta 16 bits)
  • Use peones para codificar torres fundibles (ahorro de 4 bits)

El único código restante que no se muestra en esta respuesta (por brevedad) es: romper la entrada FEN en los campos ( split /\s/) y la asignación de variables.

William Entriken
fuente
Un jugador puede promover todos sus peones (dado que es capaz de capturar peones enemigos); Qn4QQ / Qb6 / Qq1k4 / Qr6 / Qb6 / Qr6 / Qn4NK / RNB2B1R b - - 0 84
Krzysztof Szewczyk
@KrzysztofSzewczyk, sí, eso se observa arriba en PPpp=>QQq_
William Entriken
4

Los datos totales necesitan 33 bytes

(Gracias a alguien en los comentarios, me di cuenta de que esto no funciona para la promoción de peones. Actualizaré esto cuando pueda resolverlo)

para el primer byte usamos cinco bits:

  • primer bit: turno del jugador, 1 = blanco
  • segundo bit: castillo del lado del rey negro, 1 = puede castillo
  • tercer bit: castillo del lado de la reina negra, 1 = castillo de lata
  • cuarto bit: castillo del lado del rey blanco, 1 = castillo de lata
  • quinto bit: castillo del lado de la reina blanca, 1 = castillo de lata

los siguientes 32 bytes se usan para representar cada pieza de ajedrez, en un orden predefinido

  • 3 bits: representan fila
  • 3 bits: representa la columna
  • 1 bit: representa en-passant, 1 = puede en-passant
  • 1 bit: si el bit "puede pasar" es 1: indica de qué lado, 0 = izquierda
    representa si se ha capturado. 0 = no capturado
    (si puede pasar, definitivamente no se captura)

Algún código C para representar esta idea (que en realidad no funciona)

int main() {
    char b, c[32], i;

    //decode:

    FILE *p=fopen("/path/to/file.csv","r");
    fscanf(p,"%d,",&b);
    for(i=0;i<31;i++) fscanf(p,"%d,",&c[i]);
    fscanf(p,"%d",&c[31]);
    fclose(p);
    if(b&16) /* white's turn */
    else /* black's turn */
    if(b&8) /* black king side can castle */
    if(b&4) /* black queen side can castle */
    if(b&2) /* white king side can castle */
    if(b&1) /* white queen side can castle */

    for(i=0;i<32;i++) {
        int row, column;
        row=c[i]&7;
        column=c[i]&56;
        if(c[i]&64 && isPawn(c[i])) { //can en-passant
            if(c[i]&128) //can en-passant to the right
            else //can en-passant to the left
        }
        if(!(c[i]&64)) {
            if(c[i]&128) //captured
            else //not captured
        }
    }

    //encode:

    p=fopen("/path/to/file.csv","w");

    if(b&16) b&=239;
    else b|=16;
    if(black_king_side_cannot_castle) b&=247;
    if(black_queen_side_cannot_castle) b&=251;
    if(white_king_side_cannot_castle) b&=253;
    if(white_queen_side_cannot_castle) b&=254;

    for(i=0;i<32;i++) {
        c[i]=row;
        c[i]+=column*8;
        if(isPawn(c[i]) && can_en_Passant) {
            c[i]|=64;
            if(can_en_Passant_left) c[i]&=127;
            else c[i]|=128;
        }
        if(!(c[i]&64)) {
            if(isCaptured(c[i])) c[i]|=128;
            else c[i]&=127;
        }
    }
    fprintf(p,"%d,",b);
    for(i=0;i<31;i++) fprintf(p,"%d,",c[i]);
    fprintf(p,"%d",c[31]);
    fclose(p);
    return 0;
}
pastebin.com slash 0mr8spkT
fuente
-1, esta no es una respuesta ...
Pomo de la puerta
1
Su orden predefinido no será de mucha utilidad cuando un peón alcance el octavo rango y sea promovido a caballero, obispo, torre o reina.
aprensivo ossifrage
@Doorknob of Snow ok, estoy trabajando en el algoritmo, es un poco tarde en la noche y estoy cansado, así que lo estoy haciendo un poco más lento
pastebin.com slash 0mr8spkT
Bueno, entonces ¿por qué publicaste esto si ni siquiera tienes una solución?
Pomo de la puerta
3
si todavía piensan que esta respuesta es una mierda y no tiene ningún valor aquí, entonces adelante y vote para eliminarla y rechazarla y también puede eliminar mi cuenta aquí. Solo quiero compartir lo que podría pensar, ¿por qué tienen que ser tan malos?
pastebin.com slash 0mr8spkT
4

256 242 bits

Aquí hay un algoritmo de compresión básico que probablemente pueda mejorarse porque no excluye ciertas posiciones ilegales de ser representadas.

El tablero comienza con 5 bits de información de encabezado, de la siguiente manera:

0 1 1 1 1
---------
1 2 3 4 5

1: Turn (black = 1, white = 0)
2: Black can castle queen-side
3: Black can castle king-side
4: White can castle queen-side
5: White can castle king-side

Luego, una cadena de 12 bits que representa las posiciones de los reyes.

0 0 0 1 0 0 1 1 1 1 0 0
-----------------------
0 0 0 0 0 0 0 0 0 1 1 1
1 2 3 4 5 6 7 8 9 0 1 2

01 - 03: white king's rank
04 - 06: white king's file
07 - 09: white king's rank
10 - 12: white king's file

Luego, un gran número de 64 dígitos en la base 11, que luego se multiplica por 9 para agregar otro dígito al final que represente el estado de en-passant. Cada dígito en la base 11 representa un cuadrado en el tablero, con los siguientes valores posibles:

0: empty

1: white pawn
2: white knight
3: white bishop
4: white rook
5: white queen

For the black equivalent of each white piece, add 5.

Y los dígitos en la base 9:

0: no en-passant possible
1 - 8: en-passant on rank 1 - 8

11 64 × 9 es aproximadamente 2 224.57 , que requiere 225 bits para codificar. Además, los 17 bits de encabezado en la parte superior son 242 bits en total.


Gracias a ugoren por las mejoras.

Joe Z.
fuente
Esto es muy similar al algoritmo de as, pero usa posiciones de tablero en lugar de piezas en un orden predeterminado, lo que lo excluye de tener el problema de promoción de peón y permite que los datos se corten un poco.
Joe Z.
Puede guardar en-passant como un número entre 0 y 8 (¿en qué columna puede el jugador actual capturar en-passant?). 13^64 * 9es 239.99, ahorrando 11 bits. Ahorre más codificando posiciones de rey por separado.
ugoren
Según Doorknob de Snow, quien comentó mi publicación, este tipo de respuesta "no es una respuesta". Solo digo. Para su información, su comentario fue publicado antes de agregar el código C a mi respuesta.
pastebin.com slash 0mr8spkT
@ugoren: Me olvidé de eso. Tienes razón, olvidé que solo un peón puede pasar al mismo tiempo.
Joe Z.
@ace: su respuesta no es inválida porque no incluye código de codificación y decodificación; no es válido porque no tiene en cuenta el caso de promoción de peón (en cuyo caso su orden predefinido de piezas no hace nada). El problema, en esencia, pide un esquema de codificación de datos. El programa es solo algo para interactuar con eso.
Joe Z.
3

? pedacitos

(≥ 217 en el peor de los casos, 17 en el mejor de los casos, 179 para la placa inicial)


Descripción de codificación

Los metadatos adicionales consisten en el turno de quién es (un bit) y el enroque (cuatro bits, es decir, ¿puede el castillo blanco en el lado de los reyes? ¿En el lado de las reinas? Y de manera similar para el negro).

Para la posición del tablero en sí, lo codificamos como un conjunto de piezas activas. Bueno, en realidad, nos aseguramos de enumerar las piezas en un orden particular por razones que explicaré más adelante. Para cada pieza almacenamos su color (un bit), su tipo (tres bits para abarcar 6 tipos, más un tipo adicional para "peón que puede ser tomado por passant"), así como su posición.

Aquí está la parte interesante: para codificar la posición de una pieza, en lugar de almacenarla como una coordenada, almacenamos su distancia relativa de la última pieza al enumerar las piezas en orden de izquierda a derecha, de arriba a abajo (es decir, A8 , B8, ..., G1, H1). Además, almacenamos la distancia como un número de longitud variable, usando1 que significa que esta pieza está justo al lado de la anterior, 0xxpara saltar 1-3 piezas, 000xxxpara saltar 4-10 piezas, 000000xxxxpara 11-25, 0000000000xxxxxpara 26-56 y finalmente000000000000000xxx por 57-62.

Ejemplos

Hice una idea general de algunas posiciones codificadas con esta codificación, y anoté la de la posición inicial con algunos comentarios.

No sé cómo analizar el tamaño de bits en el peor de los casos, pero siguiendo los ejemplos en la esencia, creo que el algoritmo debería ser algo eficiente al menos.


Implementación de decodificador

A continuación se muestra un decodificador rápido y sucio para esta codificación (tomando como entrada los datos binarios codificados en el texto, como en el ejemplo anotado anteriormente, y omitiendo cosas que no son '0' o '1'). Produce un tablero de ajedrez unicode para stdout.

#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>

char buf[1024];
int wi = 0, ri = 0;

int read_n(int n) {
  int res = 0;
  for (int i = 0; i < n; i++) {
    res = res << 1 | (buf[ri++] == '1');
  }
  return res;
}

int read_varnum() {
  int v, c = 0;

  for (int i = 1; i <= 5; i++) {
    v = read_n(i);
    if (v != 0) return c + v;
    c += (1 << i) - 1;
  }

  assert(false); /* Shouldn't happen */
}

char *piece_to_str(int piece, int color) {       /* ↓ pawn that may be taken with en passant */
  char *pieces[] = { "♙", "♘", "♗", "♖", "♕", "♔", "♙",
                     "♟", "♞", "♝", "♜", "♛", "♚", "♟" };
  return pieces[color * 7 + piece];
}

int main(void) {
  int ch;
  while (ch = getchar(), ch != EOF) {
    if (ch == '0' || ch == '1') buf[wi++] = ch;
  }

  int board[64];
  memset(board, -1, 64 * sizeof(int));

  /* Read metadata */
  int is_white = read_n(1);
  int castling = read_n(4);

  /* Read the board state */
  int bi = -1;
  while (ri != wi) {
    int color = read_n(1);
    int kind  = read_n(3);
    int delta = read_varnum();
    board[bi + delta] = color << 8 | kind;
    bi += delta;
  }

  /* Print metadata */
  printf("  Current turn: %s's turn to play.\n", is_white? "white" : "black");
  printf("  Castling: White may castle? %s %s\n",
         castling & 0x8? "left" : "", castling & 0x4? "right" : "");
  printf("            Black may castle? %s %s\n",
         castling & 0x2? "left" : "", castling & 0x1? "right" : "");
  printf("\n");

  /* Print the board out */
  printf("+");
  for (int x = 0; x < 8; x++) printf("--");
  printf("-+\n");

  for (int y = 0; y < 8; y++) {
    printf("|");
    for (int x = 0; x < 8; x++) {
      int piece = board[y*8 + x],
          color = piece >> 8,
          kind  = piece & 0xFF;

      if (piece == -1) printf("  ");
      else printf(" %s", piece_to_str(kind, color));
    }
    printf(" |\n");
  }

  printf("+");
  for (int x = 0; x < 8; x++) printf("--");
  printf("-+\n");

  return 0;
}
Luciérnaga
fuente
No tengo idea de cuál es su peor recuento de bits, pero sospecho que es considerablemente más de 179 bits. Por ejemplo, ¿cómo manejaría su algoritmo este diseño ? (Se es válida, por cierto, lo hice usando el editor en chess.com )
aprensivo ossifrage
@squeamishossifrage que parece requerir 217 bits: gist.github.com/FireyFly/8639791 (gracias por el caso de prueba, ¡quería probarlo con uno más complicado!)
FireFly
Oye, eso no está mal. ¡Sigue adelante!
aprensivo ossifrage
2

Máx .: 184 bits, Mín .: 75 bits

Me inspiró la codificación Huffman de @ AdamSpeight para piezas para intentar crear mi propio esquema. Dudo que esto gane, pero tiene límites calculables.

Este esquema trata las piezas de ajedrez como si hubiera 11 tipos diferentes de piezas. Seguí aproximadamente el algoritmo de codificación de Huffman para agrupar estas clases por sus frecuencias y tipos reales para generar las siguientes codificaciones:

 Piece Class                | Frequency Per Team | Encoding
============================+====================+==========
 Pawn, normal               | 0 - 8              | 0
 Pawn, jumped two last turn | 0 - 1              | 1111
 Knight                     | 0 - 2              | 1000
 Bishop                     | 0 - 2              | 1001
 Queen-side rook, unmoved   | 0 - 1              | 10100
 Queen-side rook, moved     | 0 - 1              | 10101
 King-side rook, unmoved    | 0 - 1              | 10110
 King-side rook, moved      | 0 - 1              | 10111
 Queen                      | 0 - 1              | 1110
 King, unmoved              | 0 - 1              | 1100
 King, moved                | 0 - 1              | 1101

El código de cada pieza puede estar precedido por dos bits para mostrar a qué equipo pertenece ( 10para Blanco, 11para Negro). 0se puede usar para codificar espacios vacíos. Estas ideas nos permiten construir una codificación cuadrado por cuadrado para toda la placa utilizando el procedimiento que queramos. Asumiré el orden de iteración a1, b1, c1, ... f8, g8, h8. Esto significa que solo enumerar estos códigos como se muestra arriba codifica toda la información, excepto de quién es el turno. Un motor de ajedrez muy simple puede usar las "clases" para los peones, torres y reyes para determinar si el enroque y el pase son legales. Además, este esquema maneja fácilmente las promociones de peones. Si un jugador promueve un peón a una torre, se pueden usar los códigos del lado del rey o la reina siempre que se elija la variante "movida".

A excepción de las posiciones patológicas que no creo que puedan suceder, el peor de los casos para esta codificación es cuando todas las piezas aún están en el tablero y el jugador anterior movió un peón dos espacios hacia adelante. Como ejemplo, la tabla a continuación codifica 1. e4:

1101010010100010100110111010110010100110100010101101001001001100100100100000000000000101111000000000000000000011011011011011011011011011101001110001110011111101111001110011110001110110
===========================================================================
                              Black's move
1110100 111000 111001 111110 111100 111001 111000 1110110 | r n b q k b n r
    110    110    110    110    110    110    110     110 | p p p p p p p p
      0      0      0      0      0      0      0       0 | . . . . . . . .
      0      0      0      0      0      0      0       0 | . . . . . . . .
      0      0      0      0 101111      0      0       0 | . . . . P . . .
      0      0      0      0      0      0      0       0 | . . . . . . . .
    100    100    100    110      0    100    100     100 | P P P P . P P P
1010100 101000 101001 101110 101100 101001 101000 1010110 | R N B Q K B N R

Esto significa que la codificación en el peor de los casos tiene 184 bits: 1 para indicar el jugador, 32 para los espacios vacíos, 45 para los peones no movidos, 6 para el peón de salto de dos espacios, 24 para los caballeros, 24 para los obispos, 28 para las torres, 12 para las reinas y 12 para los reyes.

A medida que las piezas se mueven y se capturan, el tamaño de la codificación disminuirá. El mejor de los casos está representado por dos reyes solos en el tablero: 1 bit para indicar al jugador + 62 bits para indicar los cuadrados vacíos + 12 bits para indicar que los reyes dan una longitud mínima de 75 bits.

Volveré y editaré esta respuesta con algún código que demuestre esta codificación en acción más tarde hoy o mañana. Por ahora, tengo curiosidad por ver lo que otras personas piensan de esta codificación.

sadakatsu
fuente
1
Puedes guardar bits en las torres. Puedes determinar el lado de la reina y el rey en función de la posición, y no necesitas saber de qué lado proviene una torre movida. así que solo necesita un poco de información en la torre, movida o sin mover.
No es que Charles
... Y en realidad, almacenar esos datos en un nivel de pieza es más fácil de codificar / decodificar, pero si acaba de almacenar un marcador al principio, puede guardar bits en el peor de los casos (por ejemplo, el marcador 11001significa B'S MOVE W CAN KSC W CANT QSC B CANT KSC B CAN QSC). Eso es 4 bits en lugar de los 5 bits por lado en su codificación, o 3 bits por lado si elimina el marcador lateral en las torres. ( KSC= Castillo del lado del rey. QSC= Castillo del lado de la reina)
No es que Charles
Además, debido a las promociones, es bastante posible tener hasta 9 reinas o 10 caballeros (o cualquier otra pieza no real, no peón)
No es que Charles
1

184 bits = 23 bytes en el peor de los casos, y no demasiado complicado:

A. Qué cuadrados ocuparon: 64 bits = 8 bytes B. Qué colores para los <= 32 cuadrados ocupados: 32 bits = 4 bytes Y ahora usando solo los <= 30 cuadrados ocupados por no reyes: B. use PNBRQ codificado en radix 5, para 5 ^ 30 posibilidades; y 32 * 31 * 2 * 4 * 4 * 9 para posiciones de rey, color de movimiento, derechos de enroque en blanco y negro, cuadrado pasajero (entre 8 posibilidades más ninguna, un noveno); este número 5 ^ 30 * 32 * 31 * 2 * 4 * 4 * 9 = 266075134277343750000000000 = 2 ^ 87.782 cabe en 88 bits para un total de 64 + 32 + 88 = 184 bits para toda la codificación.

Esto se puede reducir, por ejemplo, 32 * 31 * 2 * 4 * 4 * 9 = 285696 se puede reducir a 2 * (32 * 31 + 31 * 3 + 31 * 3 + 3 * 3) * 6 = 14244, utilizando a lo sumo 6 víctimas-candidatos pasantes (incluido ninguno), y codificar los derechos de enroque y las posiciones de rey dentro del mismo conjunto utilizando los derechos de enrutamiento de hecho solo importan cuando el rey está en la casilla inicial. Esto ahorra 4 bits.

Tengo razones para creer que no es posible alcanzar 18 bytes, es decir, el número total de posiciones de ajedrez legales supera los 2 ^ 144.

Su esquema de 160 bits es muy ingenioso, pero creo que debe darse como programas de codificación / decodificación antes de tener plena confianza en él.

Warren D. Smith
fuente
1

171 bits peor de los casos:

He combinado un par de ideas, así como algunos de mis propios pensamientos.

Vamos a comenzar con una placa de 64 bits. Cada bit representa un espacio ocupado en el tablero. Se llenan a lo largo de las filas. Entonces el comienzo se ve así:1111 1111 1111 1111 0000 0000 0000 0000 0000 0000 0000 0000 1111 1111 1111 1111

Ahora, cada pieza estará representada por 4 bits. 1 ° bit: color ( 0=white, 1=black) 2 °-4 ° bits: uno de los 8 tipos.

0=king, 1=queen, 2=bishop0, 3=knight, 4=rook, 5=pawn0, 6=pawn1, 7=bishop1

Al final incluiremos un poco para designar el turno. 0=white, 1=black.

4 bits * 32 piezas = 128 bits y ya tengo 64 + 1 de turno y tablero. Eso da un total de 128 + 64 + 1 = 193 que ni siquiera he comenzado con passant o castling. Muy por encima de mi límite sin nada, ni siquiera giros. Aquí es donde comienzan los trucos.

Bien, ¿ves esos tipos arriba? Bishop0 y Bishop1? Peón0 y peón1? Esos tipos se designan así, porque nos dicen un poco para insertar después de esta pieza. Entonces Bishop0 significa que después de eso, habrá un 0, es decir, que la siguiente pieza es blanca. Bishop1 nos dice que la siguiente pieza es negra, y el peón0 y el peón1 funcionan igual. (Si esta pieza es la última pieza que se enumera, entonces nos informa sobre el próximo turno).

Mi peor caso involucra todas las piezas en el tablero, así que con 16 peones y 4 obispos, esto me ahorra 20 bits. Estoy abajo a 173.

Bueno. Por otro lado, en mi peor caso, una vez que hay 16 de un color codificado, dejamos de codificar el color, tal como lo conocemos en adelante. Mi peor caso ahora involucra una pieza blanca que llega a la esquina más alejada sin capturas. Ahí solo guardo un poco. 172)

Ahora voy a cambiar el orden en que nombro las piezas. Los nombraremos a lo largo de las columnas comenzando en el exterior. El tablero nombrado al principio seguirá siendo el mismo, pero cuando coloco piezas en él, comienzo desde los blancos de abajo a la derecha, y subo esa columna. Luego salto a la parte inferior derecha del negro y subo esa columna. Salto a la celda desconocida inferior derecha del blanco, y así sucesivamente, esto significa que mi peor caso es nuevamente el comienzo. Mi razón tiene que ver con mi truco pasajero, los siguientes dos bits que pierdo y el enroque.

Ahora, para que un peón sea promovido (como se ha discutido extensamente) se debe capturar una pieza. Por lo tanto, cuando sabemos que hay 32 piezas, solo necesitamos denotar 31 de ellas. La última pieza se identifica de forma única. Como resultado, para mí, esto solo ahorra 2 bits, porque mi última pieza podría ser un peón / alfil (que normalmente me cuesta 3 bits porque guardo uno en la siguiente pieza), cuyo color ya está determinado y solo lo fue 2 bits Estoy a 170 bits.

Cuando los peones son promovidos, simplemente cambian su tipo. Por cada pieza que sale del tablero me libero de (mínimo) 3 bits, y dos promociones de peón me cuestan 2 bits, por lo que estoy disminuyendo (lentamente) en las promociones.

Enroque. Para que ocurra el enroque, ni el rey ni la torre relevante pueden haberse movido. Por lo tanto, cuando una torre es capaz de enrocarse, tanto él como el rey estarán en sus lugares originales. Entonces, las torres capaces de enrocarse aparecerán en el mismo lugar que los reyes de ese color. Como esto es ilegal (dos reyes o tres reyes del mismo color en el tablero) y solo puede suceder en tres configuraciones posibles para cada color (izquierda, derecha, ambas torres se enumeran como reyes): la decodificación es completamente posible. Entonces, para ningún bit hemos codificado el enroque.

De paso Aquí también usaremos posiciones ilegales. Solo un peón puede estar en peligro de pasarse a la vez. Debe estar en su cuarta fila. El peón que sea vulnerable será 'volteado' a su fila de inicio, cambiado con lo que esté allí. Como ese peón está en su propia primera fila, una posición ilegal, la situación será obvia para el decodificador, revertirá las posiciones y marcará el peón como vulnerable al paso.

Necesitábamos manipular el pedido porque la última pieza tiene que ser 'identificada de manera única'. En un orden estándar, no podríamos saber si la torre en la esquina trasera podría enrocarse, eso no se sabe. Cuando trabajamos desde afuera hacia adentro, garantizamos que donde sea que esa torre esté 'listada', ya sea en su propia esquina, o en el medio del tablero porque se cambió con un peón vulnerable al paso, habrá una pieza listada después es así que nos dicen el tipo de torre. Sabemos que habrá una pieza después porque, para que un peón sea vulnerable, debe haber un peón en su interior (que se codificará más adelante según las instrucciones anteriores).

Ah, y para ayudar a asegurarnos de que el peor de los casos involucra a todas las piezas en el tablero, una vez que tengamos menos de 32 piezas, podemos usar el tablero de 64 bits para identificar las posiciones de turno y ocupadas usando 0 para representar piezas cuando el blanco gire y 1 cuando sea negro gire.

Así que nos pusimos en marcha y enrocamos gratis. Recogimos la última pieza gratis, aunque tomó un poco de tiempo para que la jugada fuera agradable con las reglas pasantes y de enroque. Eliminamos 20 bits en las piezas estándar. Creo que el peor de los casos aquí involucra un peón blanco midde movido hacia adelante y una pieza negra entre él y su reina mientras todas las piezas están en el tablero. Comprobación rápida doble: se captura la primera pieza: llámelo un peón, a 3 bits del tablero en el peón, 3 bits en el tablero en forma de una última pieza, un bit en el marcador de turno que desaparece. Promueve dos peones de 2 bits en el tablero. Ah maldición, estoy en 171.

EDITAR He agregado código para un decodificador (¿funciona?) - en R - a continuación. Toma vectores de booleanos como entrada - (lo siento, no soy capaz de codificar bien nada que me permita usar los bits) También he incluido la posición de inicio.

separate = function(vec){
    #Using a boolean vector (sorry R doesn't handle bits well and this will build quickest)
    board = matrix(vec[1:64],8,8,byrow=T)
    npieces = min(sum(board),64-sum(board))
    n = length(vec)
    a = vec[65:n]
    counter = 0
    pieces = list()
    white = 0
    Letters=c(letters,LETTERS)
    for (i in 1:npieces){
        col = ifelse(a[1],"black",{white=white+1;"white"})
        typ = a[2:4]
        a=a[-(1:4)]
        num = 4*typ[1] + 2*typ[2] + typ[3]
        type = switch(letters[num+1],a="king",b="queen",c="knight",d="rook",e="bishop0",f="bishop1",g="pawn0",h="pawn1")
        if (num > 3) {
            if(num%%2){
                a = c(T,a)
            } else {
                a = c(F,a)
            }
            type = substr(type,1,nchar(type)-1)
        }
        pieces[[Letters[i]]] = list(color=col,type=type)
        if (length(pieces)==31&&npieces==32) {
            col = ifelse(16-white,{white=white+1;"white"},"black")
            type = "TBD"
            pieces[[Letters[i+1]]] = list(color=col,type=type)
            break
        }
    }

    if (npieces==32) {
        f=function(y){sum(sapply(pieces,function(x)x$type==y))}
        if (f("pawn")<16) {pieces[[32]]$type="pawn"}
        if (f("bishop")<4) {pieces[[32]]$type="bishop"}
        if (f("knight")<4) {pieces[[32]]$type="knight"}
        if (f("queen")<2)  {pieces[[32]]$type="queen"}
        if (f("king")<2)   {pieces[[32]]$type="king"}
        if (f("rook")<(6-f("king"))) {pieces[[32]]$type="rook"}
    }
    return(list(board,pieces,turn=ifelse(a[length(a)],"black","white")))
}


fillboard = function(out) {
    board = out[[1]]
    pieces = out[[2]]
    turn = out[[3]]
    lpieces = lapply(pieces,function(x) paste(substr(x$color,1,1),x$type))
    game = matrix("     ",8,8)
    #Start with corners.
    a = c(1,57,8,64)
    #Then kings
    b = c(25,32)
    #Then rooks in en passant
    c = c(4,60,5,61)
    #Then kings in en passant
    d = 28:29
    exceptions = list(a,b,c,d)
    for (places in exceptions) {
        c= which(board[places])
        if (length(c)) {
            repl = lpieces[1:length(c)]
            game[places[c]] = unlist(repl)
            board[places] = F
            lpieces = lpieces[-(1:length(c))]
        }
    }
    #Loop through rows.
    for (i in c(1:4,8:5)) {
        j = which(board[i,])
        if (length(j)) {
            repl = lpieces[1:length(j)]
            game[i,j] = unlist(repl)
            board[i,j] = F
            lpieces = lpieces[-(1:length(j))]
        }
    }
    return(matrix(unlist(game),8,8,F))
}

swapillegal = function(matr) {
    mat = matr
    if (any(mat[8,]=="b pawn")) {
        j = which(mat[8,]=="b pawn")
        mat[8,j] = mat[5,j]
        mat[5,j] = "b pawn-e"
    }
    if (any(mat[1,]=="w pawn")) {
        j = which(mat[1,]=="w pawn")
        mat[1,j] = mat[4,j]
        mat[4,j] = "w pawn-e"
    }

    if (sum(mat[8,]=="b king") > 1) {
        j = which(mat[8,-4]=="b king")
        j[j==7] = 8
        mat[8,j] = "b rook-c"
    }
    if (sum(mat[1,]=="w king") >1) {
        j = which(mat[1,-4]=="w king")
        j[j==7] = 8
        mat[1,j] = "w rook-c"
    }
    return(mat)
}

decode = function(vec) {
    a = separate(vec)
    b = fillboard(a)
    c = swapillegal(b)
    list(board=c,turn=a[[3]])
}


startboard = c(rep(T,16),rep(F,32),rep(T,16))
#Re-ordering -- first spots will be the corners. Then kings. then en passant positions of those spots
pieces = c(F,F,T,T,F,F,T,T,T,F,T,T,T,F,T,T,F,F,F,F,T,F,F,F,F,F,T,F,F,T,F,F,F,F,T,F,T,F,F,F,T,F,F,T,T,F,T,T,F,T,T,F,T,T,F,T,T,F,T,T,F,T,T,F,T,T,T,F,T,F,T,T,F,T,F,F,T,T,T,F,T,F,T,F,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F)
########## w rook -w rook -B rook -B rook -W king -B king -w kni  -w bi 0 -w Q  -w Bi 0 -w kni-w p0   - 2   -   3 -  4  - 5   -  6  -  7  -w p1 -b kni-b bi1  -b q  -b bi1  -b kni-b p1   -2    - 3   - 4   - 5   - 6   - b p0- implicit b p0.
#After the kings come all the prior en passant positions. which are empty at start. Then we start at whites bottom right, and move across rows to middle. Then we go to blacks bottom left, and fill across to the middle.
#Changing start to properly encode rooks for castling
newpieces= c(F,F,F,F,F,F,F,F,T,F,F,F,T,F,F,F ,pieces[-(1:16)])
test2 = decode(c(startboard,newpieces))

Este código construye 4 funciones. Uno que hace una separación básica de las piezas y la estructura del tablero, así como averiguar el tipo de pieza y cualquier pieza 'implícita'. La siguiente función completa la estructura del tablero con esas piezas en un orden ligeramente extraño (y diferente al de mi algoritmo inicial) [explicado en los comentarios del código]. La siguiente función toma el tablero lleno y detecta cualquier posición ilegal; luego las repara y cambia el nombre de los peones que son vulnerables a pasar "x peón-e" y cualquier torre que pueda formar "x rook-c". La función final es un contenedor que ejecuta esas funciones en orden y proporciona una salida que es la placa actual, así como el turno.

También he incluido la codificación de la posición de inicio (aunque para verla tendrás que llamar c(startboard,newpieces) y el código llama a la función de contenedor en esa posición.

usuario5957401
fuente
Esto es interesante. Me encantaría ver una implementación funcional como prueba de concepto.
Mego
La implementación suele ser unos pocos pasos más allá de la prueba de concepto, pero he agregado un decodificador. Está en R y, por lo tanto, utiliza booleanos en lugar de bits (lo siento, no quería usar demasiado tiempo). Pero creo que debería ser una prueba de concepto.
user5957401
0

229/226 bits

Esto no resulta ser muy exitoso, pero podría salvar a otras personas por el mismo camino.

La versión simple:

  • 1 poco para quién es el turno
  • 4 bits para las cuatro posibilidades de enroque
  • 3bits para las posibilidades pasantes . Esto tiene más profundidad que al principio entendí. En passant debe hacerlo un peón que se mueva del mismo rango (fila) que el peón que se captura. El análisis de casos indica que una vez que sepamos cuántos peones del color que se movieron por última vez han avanzado exactamente dos cuadrados, habrá a lo sumo 6 casos en passant (incluido el caso de que no haya peón vulnerable a passant ). El peor de los casos son 5 peones (potencialmente todos vulnerables: p. Ej.PpPPpPPp tiene cinco vulnerables P). Con 6 peones hay como máximo 2 peones enemigos en el mismo rango, cada uno de los cuales puede amenazar a lo sumo 2 peones al pasar . Por lo tanto, necesitamos ceil(lg 6) = 3bits aquí.

Luego el tablero. El tablero tiene 64 cuadrados, por lo que un índice cuadrado puede codificarse en 6 bits. Enumeramos a los hombres por rango, alternando colores, comenzando con el rey.

  • 6bits: posición del rey blanco. (Garantizado para estar en el tablero).
  • 6bits: posición del rey negro. (Garantizado para estar en el tablero. En el peor de los casos en que el rey blanco está en una esquina, hay 60 lugares posibles en los que podría estar; en el mejor de los casos en que el blanco no está en un borde, hay 55).
  • 6bits: posición de la reina blanca. Si no hay una reina blanca, repite la posición del rey blanco como una señal.
  • Para cada reina blanca adicional, un 1bit seguido de 6 bits para la posición.
  • Un 0poco
  • Lo mismo para la (s) reina (s) negra (s).
  • Proceso similar para torres, obispos, caballeros y peones, aunque podemos omitir un color si ya tenemos 16 hombres de ese color.
  • Eliminar el 0bit final .

Esto cuesta ciertos 12bits para los reyes y 2*7*5-1 = 69bits para los otros hombres. En el peor de los casos en que los 32 hombres están en el tablero, cuesta 7un poco para cada hombre que no sean los reyes, para un total de 12 + 7*30 - 1 = 221 bits. Entonces, con los 8bits iniciales para el estado global tenemos 229 bits .


La versión avanzada:

Mediante el uso de la codificación aritmética podemos operar en lg num_possibilitieslugar de ceil(lg num_possibilities)y simplemente tomar uno ceilal final.

  • 1 poco para quién es el turno
  • 4 bits para las cuatro posibilidades de enroque
  • lg 6bits para las posibilidades pasantes .
  • 6 pedacitos para el rey blanco
  • lg 60 bits (peor caso) para el rey negro
  • lg 63 bits (porque no quiero complicarlo al nivel de mirar cheques) para la reina blanca, usando la posición del rey blanco si no hay ninguno
  • Por cada reina blanca adicional, un 1poco seguido de lg 62,lg 61 , etc. bits para su posición.
  • Un 0poco
  • lg 63 bits (o menos, si hubiera reinas blancas) para la reina negra.
  • etc.

El enésimo hombre que está realmente presente tiene 66-nvalores posibles. Si falta un tipo para un color, gastamos 66-#men so farbits en grabar eso (más un bit para el separador). Los casos extremos son:

  1. Todos los hombres presentes, incluyendo al menos un peón no promocionado de cada lado. Gastamos 5+lg 6en estado global, 6+lg 60en reyes, 29en bits separadores y SUM_{n=32}^{63} lg nbits en posiciones. Gran total:ceil(225.82) bits. Decepcionante.
  2. Solo quedan peones no promocionados. Gastamos 5+lg 6en el estado global, 6+lg 60en los reyes,29 en los bits separadores, 8*lg 63diciendo que no hay otras piezas, y SUM_{n=48}^{63} lg nen las posiciones de los peones. Gran total: ceil(188.94)bits. Mejor: al guardar la segunda torre, caballero y alfil para cada lado, hemos avanzado un poco.

Entonces, el peor de los casos parece ser 226 bits , para un ahorro miserable de 3.

Definitivamente podemos mejorar en el caso promedio al codificar los peones antes que las piezas, ya que están restringidos a 48 cuadrados en lugar de los 64 completos. Sin embargo, en el peor de los casos, todos los hombres están en el tablero y todos los peones han sido promovidos, creo esto terminaría costando 2 bits más porque necesitaríamos una bandera de "no peones" en lugar de poder contar a los hombres.

Peter Taylor
fuente
0

Este es un tema de discusión en los círculos de ajedrez.

Aquí hay una prueba muy simple con 164 bits https://groups.google.com/forum/#!topic/rec.games.chess.computer/vmvI0ePH2kI 155 se muestra aquí http://homepages.cwi.nl/~tromp /chess/chess.html

Estrategia sobre simplificada:

  • Limite los peones al lugar donde se pueden encontrar los peones
  • Limite los ejércitos para considerar piezas originales y posibles promociones de peones.
  • Piense detenidamente sobre las promociones y situaciones donde las promociones no son posibles.
William Entriken
fuente
2
Las respuestas de solo enlace no son buenas respuestas. Debe proporcionar la respuesta completa dentro de su publicación, no solo algunos enlaces a la respuesta. Y si su respuesta no es su propio trabajo, probablemente debería hacer que su publicación sea un wiki comunitario.
pastebin.com slash 0mr8spkT
La publicación es original. Agregar detalles para responder.
William Entriken
1
Este es un ejemplo de por qué incluye el contenido en su respuesta. El segundo enlace está muerto. Es esto? tromp.github.io/chess/chess.html
mbomb007
-2

Min: 0 bits

Max: 1734 243 bits (4.335 4.401 bits / tablero amortizado)

Esperado: 351 177 bits (4.376 4.430 bits / tablero amortizado)

Como puedo determinar la entrada y la salida que quiera, decidí seguir codificando la historia del juego hasta este momento. Una ventaja es que la información adicional de quién es el turno, pasa y quién tiene la capacidad de atacar dónde se puede derivar y no codificar.

Intento 1:

Ingenuamente pensé que puedo codificar cada movimiento en 12 bits, 4 tripletas de la forma (inicio x, inicio y, final x, final y) donde cada uno es de 3 bits.

Asumiríamos la posición inicial y moveríamos las piezas desde allí con las blancas primero. El tablero está dispuesto de tal manera que (0, 0) es la esquina inferior izquierda del blanco.

Por ejemplo el juego:

  e4    e5
 Nf3    f6
Nxe5  fxe5
...    ...

Sería codificado como:

100001 100010 100110 100100
110000 101010 101110 101101
101010 100100 101101 100100
...

Esto lleva a una codificación de 12 m bits, donde m es el número de movimientos realizados

Por un lado, esto podría ser realmente grande, por otro lado, puede considerar que cada movimiento es su propio juego, por lo que cada codificación realmente codifica m "tableros de ajedrez". Si amortizaste esto, obtienes que cada "tablero de ajedrez" es de 12 bits. Pero siento que esto es un poco trampa ...

Intento 2:

Me di cuenta de que cada movimiento en el intento anterior codifica muchos movimientos ilegales. Así que decidí codificar solo movimientos legales. Enumeramos posibles movimientos de la siguiente manera, numera cada cuadrado de manera que (0, 0) → 0, (1, 0) → 1, (x, y) → x + 8 y. Itere a través de las fichas y compruebe si hay una pieza y si puede moverse. Si es así, agregue las posiciones a las que puede ir a una lista. Elija el índice de la lista que es el movimiento que desea hacer. Agregue ese número al total acumulado de movimientos ponderados por 1 más el número de movimientos posibles.

Ejemplo como el anterior: desde la posición inicial, la primera pieza que puede moverse es el caballero en el cuadrado 1, puede moverse al cuadrado 16 o 18, así que agréguelos a la lista [(1,16),(1,18)]. El siguiente es el caballero en el cuadrado 6, agregue sus movimientos. En general obtenemos:

[(1,16),(1,18),(6,21),(6,23),(8,16),(8,24),(9,17),(9,25),(10,18),(10,26),(11,19),(11,27),(12,20),(12,28),(13,21),(13,29),(14,22),(14,30),(15,23),(15,31)]

Como queremos el movimiento (12, 28), codificamos esto como 13 en la base 20, ya que hay 20 movimientos posibles.

Entonces ahora tenemos el número de juego g 0 = 13

A continuación, hacemos lo mismo para el negro, excepto que numeramos las fichas al revés (para que sea más fácil, no obligatorio) obtener la lista de movimientos:

[(1,16),(1,18),(6,21),(6,23),(8,16),(8,24),(9,17),(9,25),(10,18),(10,26),(11,19),(11,27),(12,20),(12,28),(13,21),(13,29),(14,22),(14,30),(15,23),(15,31)]

Como queremos el movimiento (11, 27), codificamos esto como 11 en la base 20, ya que hay 20 movimientos posibles.

Entonces ahora obtenemos el número de juego g 1 = (11 ⋅ 20) + 13 = 233

A continuación obtenemos la siguiente lista de movimientos para las blancas:

[(1,16),(1,18),(3,12),(3,21),(3,30),(3,39),(4,12),(5,12),(5,19),(5,26),(5,33),(5,40),(6,12),(6,21),(6,23),(8,16),(8,24),(9,17),(9,25),(10,18),(10,26),(11,19),(11,27)(13,21),(13,29),(14,22),(14,30),(15,23),(15,31)]

Como queremos el movimiento (6, 21), codificamos esto como 13 en la base 29 ya que hay 29 movimientos posibles.

Entonces ahora obtenemos el número de juego g 2 = ((13 ⋅ 20) + 11) 20 + 13 = 5433

A continuación obtenemos la siguiente lista de movimientos para las negras: [(1,11),(1,16),(1,18),(2,11),(2,20),(2,29),(2,38),(2,47),(3,11),(4,11),(4,18),(4,25),(4,32),(6,21),(6,23),(8,16),(8,24),(9,17),(9,25),(10,18),(10,26),(12,20),(12,28),(13,21),(13,29),(14,22),(14,30),(15,23),(15,31)]

Como queremos el movimiento $ (10, 18) $ (10, 18)

Entonces ahora obtenemos el número de juego g 3 = (((19 ⋅ 29 + 13) 20) + 11) 20 + 13 = 225833

Y continúe este proceso para todos los movimientos restantes. Puedes pensar en g como la función g (x, y, z) = x y + z. Así g 0 = g (1, 1, 13), g 1 = g (g (1, 1, 11), 20, 13), g 2 = g (g (g (1, 1, 13), 20, 11), 20, 13), g 3 = g (g (g (g (1, 1, 19), 29, 13), 20, 11), 20, 13)

Para decodificar un número de juego g 0 , comenzamos en la posición inicial y enumeramos todos los movimientos posibles. Luego calculamos g 1 = g 0 // l , m 0 = g 0 % l , donde l es el número de movimientos posibles, '//' es el operador de división entera y '%' es el operador de módulo. Debe sostener que g 0 = g 1 + m 0 . Luego hacemos el movimiento m 0 y repetimos.

Del ejemplo anterior si g 0 = 225833, entonces g 1 = 225833 // 20 = 11291 ym 0 = 225833% 20 = 13. A continuación g 2 = 11291 // 20 = 564 ym 1 = 11291% 20 = 11. Luego g 3 = 11291 // 20 = 564 y m 2 = 11291% 20 = 11. Por lo tanto, g 4 = 564 // 29 = 19 y_m_ 3 = 564% 29 = 13. Finalmente g 5 = 19 // 29 = 0 ym 4 = 19% 29 = 19.

Entonces, ¿cuántos bits se usan para codificar un juego de esta manera?

Por simplicidad, digamos que siempre hay 20 movimientos cada turno y para el peor de los casos siempre elegimos el más grande, 19. El número que obtendremos es 19 ⋅ 20 m

+ 19 ⋅ 20 m-1 + 19 ⋅ 20 m-2 + ⋯ + 19 ⋅ 20 + 19 = 20 m + 1 - 1 donde _m es el número de movimientos. Para codificar 20 m + 1 - 1 necesitamos aproximadamente log 2 (20 m + 1 ) bits, que es aproximadamente (m + 1) ∗ log 2 (20) = 4.3219 ∗ (m + 1)

En promedio m = 80 (40 movimientos por jugador), por lo que se necesitarían 351 bits para codificar. Si estuviéramos grabando muchos juegos necesitaríamos una codificación universal ya que no sabemos cuántos bits necesitará cada número

El peor de los casos cuando m = 400 (200 movimientos por jugador), por lo que se necesitarían 1734 bits para codificar.

Tenga en cuenta que la posición que queremos codificar nos debe ser dada a través del camino más corto para llegar siguiendo las reglas. Por ejemplo, el juego teorizado aquí no necesita m = 11741 para codificar la posición final. En su lugar, ejecutamos una búsqueda Breadth-First para encontrar la ruta más corta a esa posición y codificarla en su lugar. No sé qué tan profundo tendríamos que llegar para enumerar todas las posiciones de ajedrez, pero sospecho que 400 es una sobreestimación.

Cálculo rápido

Hay 12 piezas únicas o el cuadrado puede estar vacío, por lo que colocarlas en un tablero de ajedrez es 13 64 . Esta es una gran sobreestimación ya que incluye muchas posiciones inválidas. Cuando estamos m se mueve en el juego que hemos creado unos 20 m posiciones. Entonces estamos buscando cuando 20 m = 13 64 . Registre ambos lados para obtener m = 64 * log 20 (13) = 54.797. Esto muestra que deberíamos poder llegar a cualquier posición en 55 movimientos.

Ahora que calculé que el peor de los casos sería m = 55 no m = 400, editaré mis resultados. Para codificar una posición donde m = 55 toma 243 bits. También voy a decir que el caso promedio es de alrededor de m = 40, que toma 177 bits para codificar.

Si utilizamos el argumento de amortización de antes, estamos codificando 400 "tableros de ajedrez" en 1734 bits, de modo que obtenemos que cada "tablero de ajedrez" ocupa 4.335 bits en el peor de los casos.

Tenga en cuenta que g = 0 denota un juego válido, aquel en el que la pieza en el cuadrado más bajo se mueve al cuadrado más bajo que puede.

Notas adicionales:

Si desea referirse a una posición específica en el juego, es posible que deba codificar el índice. Esto se puede agregar manualmente, por ejemplo, concatenar el índice al juego, o agregar un movimiento "final" adicional como el último movimiento posible en cada turno. Esto ahora puede dar cuenta de los jugadores que conceden, o 2 seguidos para denotar que los jugadores aceptaron un empate. Esto solo es necesario si el juego no terminó en jaque mate o estancado según la posición, en este caso está implícito. En este caso, lleva el número de bits necesarios en promedio a 356 y, en el peor de los casos, a 1762.

edggy
fuente
1
Su argumento de "amortización" no funciona. El objetivo es codificar una placa dada por el usuario. No puede dividir el costo de codificar esta placa entre las 400 placas auxiliares que podría generar a lo largo del camino. (Esto solo estaría bien si el usuario permitiera que esos 400 tableros fueran elegidos independientemente, y no estuvieran limitados por el requisito de formar un juego de ajedrez). Además, un juego de ajedrez teóricamente puede tomar muchos miles de movimientos , y el OP es claro sobre estar interesado en el peor de los casos.
Anders Kaseorg
@AndersKaseorg: Muy cierto. Realmente depende del objetivo. Si está tratando de almacenar un juego completo con todos los otros algoritmos, tomaría m * c bytes donde m es el número de movimientos y c es el tamaño de su salida. Entonces, si estás tratando de almacenar un juego completo de 80 movimientos usando la solución de 160 bits, tomaría 12800 bits, mientras que el mío solo tomaría 351. Por el bien de la competencia, admito que tienes razón, pero pensé que era una buena propiedad para señalar, ya que es muy común querer almacenar juegos completos y no solo tableros.
nervioso
El objetivo es inequívoco. “El objetivo es hacer la representación más pequeña de un tablero de ajedrez que pueda usarse (una vez decodificado) para determinar todas las posibilidades de movimiento para un jugador en ese turno. ... Su puntaje se determina en el peor de los casos: el tamaño máximo posible en bits ".
Anders Kaseorg
@AndersKaseorg: nunca dije que fuera ambiguo. Simplemente decidí tomar un enfoque diferente. Una cosa a tener en cuenta es que para encontrar el tablero más pequeño usando mi algoritmo, necesito el camino más pequeño para llegar a esta posición. Por ejemplo, en el juego de turno 11741 que vinculaste para llegar a la misma posición del tablero, no necesito seguir ese camino si todo lo que nos importa es el tablero. Entonces, para codificar el juego vinculado, solo encuentro el juego más corto que queda con 2 reyes en esas casillas que solo pueden tener 200 turnos o menos. Esto se puede hacer con una búsqueda profunda primero.
nervioso
Usar un juego equivalente más corto está bien, si realmente puedes probar que cada posición es alcanzable en 200 turnos o menos (en este momento esto parece una simple suposición). También deberás tener en cuenta las posiciones de ajedrez con más de 100 movimientos legales , a menos que puedas probar que no surgen dentro de tu construcción. Dividir su resultado por el número de movimientos en el juego todavía no está permitido por las reglas de este desafío.
Anders Kaseorg