pioz / chess

A fast chess library that use bitboards to play chess with Ruby
GNU Lesser General Public License v3.0
59 stars 17 forks source link

Lichess coordinate notation for castling #26

Closed juhoha closed 2 years ago

juhoha commented 2 years ago

Ran into issues with coordinate notation using data from Lichess. The castling's presented as e8h8 instead of e8g8: example Wikipedia and this gem follow the latter. Not sure if this is some wider spread alternative convention or a Lichess oddity.

Any way made a local quickfix to get these games to parse. Here's the patch I used, in case interested:

diff --git a/lib/chess/game.rb b/lib/chess/game.rb
index abae061..5f0d5d7 100644
--- a/lib/chess/game.rb
+++ b/lib/chess/game.rb
@@ -143,6 +143,23 @@ module Chess

     private

+    # For some reason Lichchess presents coordinate notation castling as
+    # e8h8 instead of e8g8, eg:
+    # https://explorer.lichess.ovh/masters?variant=standard&fen=rnbqkbnr%2Fpppppppp%2F8%2F8%2F8%2F8%2FPPPPPPPP%2FRNBQKBNR+w+KQkq+-+0+1&play=b2b3%2Cg8f6%2Cc1b2%2Ce7e6%2Ce2e3%2Cf8e7%2Cf2f4&since=1952&until=2022
+    def patch_lichess_coordinate_notation!(expand)
+      allowed = self.board.to_fen.split[2] # Ensure king's in from square
+      castling = [
+        ['k', 'e8', 'h8', 'g8'],
+        ['K', 'e1', 'h1', 'g1'],
+        ['q', 'e8', 'a8', 'c8'],
+        ['Q', 'e1', 'a1', 'c1']
+      ]
+      _allowed_token, _from, _to, patched = castling.find { |a, f, t|
+        expand[:from] == f && expand[:to] == t && allowed.include?(a)
+      }
+      expand[:to] = patched if patched
+    end
+
     # Expand the short algebraic chess notation string `notation` in a hash like this:
     #
     #     Ngxe2 ==> { name: 'N', dis: 'g', from: nil, to: 'e2', promotion: nil }
@@ -155,6 +172,7 @@ module Chess
           promotion: match[4]       # Promote with
         }
         expand[:from] = match[2] if match[2] && match[2].size == 2
+        patch_lichess_coordinate_notation!(expand)
         return expand
       elsif SHORT_CASTLING_REGEXP.match?(notation)
         return { name: 'K', dis: nil, from: 'e8', to: 'g8', promotion: nil } if self.board.active_color # black king short castling
pioz commented 2 years ago

Seems that some computer protocols use this notation for castling e8h8. https://github.com/niklasf/shakmaty/issues/13

I'll try to add support to this notation with some tests also.

pioz commented 2 years ago

Pushed new chess version 0.3.3 that supports UCI castling notation.

@juhoha let me know if this works for you. Thanks.

juhoha commented 2 years ago

Cheers! Don't think I've got my project lying around anymore – was bit of a fire and forget let's these games parsed kind of an ordeal :-) Anyway I think this ought to take care of it for anyone that follows and wants to do Lichess parses!

I'm not super familiar with the code base so I originally had a weird sanity check of "check the FEN if castling is allowed" to prevent edge cases where say a rook is in king's starting position and tries to move back to a rook's starting position. Was worried that might be misinterpreted as a castling as the notation (eg. e8h8) is ambiguous (or rather game state -dependant): Assuming a legal move it might be a king castling or a rook/queen actually moving from e8 to h8. Not sure if this ever actually an issue or if there was already something handling it. If not, I think handling that case was dropped when cleaning the code.