Programmer Puzzle: Encoding a chess board state throughout a game

前端 未结 30 1542
闹比i
闹比i 2021-01-29 17:16

Not strictly a question, more of a puzzle...

Over the years, I\'ve been involved in a few technical interviews of new employees. Other than asking the standard \"do you

30条回答
  •  说谎
    说谎 (楼主)
    2021-01-29 17:32

    At each position get the number of all possible moves.

    next move is generated as

    index_current_move =n % num_of_moves //this is best space efficiency
    n=n/num_of_moves
    

    provably best space efficiency for storing randomly generated game and need approx 5 bits/move on average since you have 30-40 possible moves. Assembling storage is just generating n in reverse order.

    Storing position is harder to crack, because of great redundancy. (There can be up to 9 queens on board for one site but in that case there are no pawns, and bishops if on the board are on opposite colored squares) but generally is like storing combination of same pieces over remaining squares.)

    EDIT:

    Point in saving moves is to store only the index of move. Instead of storing Kc1-c2 and trying to reduce this info we should add only index of move generated from deterministic movegenerator(position)

    At each move we add information of size

    num_of_moves = get_number_of_possible_moves(postion) ;
    

    in pool and this number cannot be reduced

    generating information pool is

    n=n*num_of_moves+ index_current_move
    

    extra

    If there is only one move available in final position, save as number of previously done forced moves. Example: if starting position has 1 forced moves for each side (2 moves) and we want to save this as one move game, store 1 in pool n.

    example of storing into info pool

    Lets suppose that we have known starting positions and we do 3 moves.

    In first move there are 5 available moves, and we take move index 4. In second move there are 6 available moves and we take position index 3 and in 3th move there are 7 moves available for that side and he chose to pick the move index 2.

    Vector form; index=[4,3,2] n_moves=[5,6,7]

    We are encoding this info backwards, so n= 4+5*(3+6*(2))=79 (no multiplying by 7 needed)

    How to unloop this? First we have position and we find out that there are 5 moves available. So

    index=79%5=4
    n=79/5=15; //no remainder
    

    We take move index 4 and examine position again and from this point we find out that there are 6 possible moves.

    index=15%6=3
    n=15/6=2
    

    And we take move index 3 which gets us to a position with 7 possible moves.

    index=2%7=2
    n=2/7=0
    

    We do last move index 2 and we reach final position.

    As you can see the time complexity is O(n) ansd space complexity is O(n). Edit: time complexity is actually O(n^2) because the number you multipy by increases, but there should be no problem storing games up to 10,000 moves.


    saving position

    Can be done close to optimum.

    When we find out about information and storing informations let me talk more about it. General idea is to decrease redundancy (I will talk about that later). Lets presume that there were no promotions and no taking so there are 8 pawns, 2 rooks, 2 knights, 2 bishops 1 king and 1 queen per side.

    What do we have to save: 1. position of each peace 2. posibilities of castling 3. possibilities of en-passant 4. side that has move avaliable

    Let's suppose that every piece can stand anywhere but not 2 pieces at same place. Number of ways 8 pawns of same color can be arranged on board is C(64/8) (binomial) which is 32 bits, then 2 rooks 2R-> C(56/2), 2B -> C(54/2), 2N->C(52/2), 1Q->C(50/1), 1K -> C(49/1) and same for other site but starting with 8P -> C(48/8) and so on.

    Multiplying this together for both sites get us number 4634726695587809641192045982323285670400000 which is approx 142 bits, we have to add 8 for one possible en-passant (en-passant pawn can be in one of 8 places), 16 (4 bits) for castling limitations and one bit for site that has move. We end up with 142+3+4+1=150bits

    But now let's go on the hunt for redundancy on the board with 32 pieces and no taking.

    1. both black and white pawns are on same column and facing each other. Each pawn is facing other pawn that means that white pawn can be at most at 6th rank. This bring us 8*C(6/2) instead of C(64/8)*C(48/8) which decrease information by 56 bits.

    2. possibility of castling is also redundant. If rooks are not on starting place there is no castling possibility whit that rook. So we can imaginaly add 4 squares on board to get the extra info if castling whit this rook is possible and remove 4 castling bits. So instead of C(56/2)*C(40/2)*16 we have C(58/2)*C(42/2) and we lost 3.76 bits (almost all of 4 bits)

    3. en-passant: When we store one of 8 en passant possibilites, we know position of black pawn and reduce informational redindancy (if it is white move and has 3th pawn en-passant that mean that black pawn is on c5 and white pawn is either c2,c3 or c4) so insted of C(6/2) we have 3 and we lost 2.3 bits. We decrease some redundancy if we store whit en-passant number also side from which can be done (3 possibilities-> left,right,both) and we know the possiton of pawn that can take en passant. (for instance from prevous en passant example whit black on c5 what can be in left, right or both. if it is on one site we have 2*3 (3 for storing psissibilites and 2 possible moves for black pawn on 7th or 6 rank) insted of C(6/2) and we reduce by 1.3 bits and if on boths sides we reduce by 4.2 bits. That way we can reduce by 2.3+1.3=3.6 bits per en passant.

    4. bishops: bisops can be on opostite squares only, this reduce redundancy by 1 bit for each site.

    If we sum up we need 150-56-4-3.6-2=85bits for storing chess position if there were no takings

    And probably not much more if there are takings and promotions taken in account (but i will write about that later if somebody will find this long post usefull)

提交回复
热议问题