chess_engine_rb 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +83 -0
- data/lib/chess_engine/data_definitions/README.md +10 -0
- data/lib/chess_engine/data_definitions/board.rb +192 -0
- data/lib/chess_engine/data_definitions/components/castling_rights.rb +48 -0
- data/lib/chess_engine/data_definitions/components/persistent_array.rb +114 -0
- data/lib/chess_engine/data_definitions/events.rb +174 -0
- data/lib/chess_engine/data_definitions/piece.rb +159 -0
- data/lib/chess_engine/data_definitions/position.rb +137 -0
- data/lib/chess_engine/data_definitions/primitives/castling_data.rb +61 -0
- data/lib/chess_engine/data_definitions/primitives/colors.rb +26 -0
- data/lib/chess_engine/data_definitions/primitives/core_notation.rb +111 -0
- data/lib/chess_engine/data_definitions/primitives/movement.rb +52 -0
- data/lib/chess_engine/data_definitions/square.rb +98 -0
- data/lib/chess_engine/engine.rb +299 -0
- data/lib/chess_engine/errors.rb +35 -0
- data/lib/chess_engine/event_handlers/base_event_handler.rb +112 -0
- data/lib/chess_engine/event_handlers/castling_event_handler.rb +48 -0
- data/lib/chess_engine/event_handlers/en_passant_event_handler.rb +59 -0
- data/lib/chess_engine/event_handlers/init.rb +41 -0
- data/lib/chess_engine/event_handlers/move_event_handler.rb +144 -0
- data/lib/chess_engine/formatters/eran_formatters.rb +71 -0
- data/lib/chess_engine/formatters/init.rb +19 -0
- data/lib/chess_engine/formatters/validation.rb +54 -0
- data/lib/chess_engine/game/history.rb +25 -0
- data/lib/chess_engine/game/init.rb +15 -0
- data/lib/chess_engine/game/legal_moves_helper.rb +126 -0
- data/lib/chess_engine/game/query.rb +168 -0
- data/lib/chess_engine/game/state.rb +198 -0
- data/lib/chess_engine/parsers/eran_parser.rb +85 -0
- data/lib/chess_engine/parsers/identity_parser.rb +18 -0
- data/lib/chess_engine/parsers/init.rb +21 -0
- data/lib/chess_engine_rb.rb +46 -0
- metadata +112 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'immutable'
|
|
4
|
+
require_relative 'query'
|
|
5
|
+
require_relative 'history'
|
|
6
|
+
require_relative '../errors'
|
|
7
|
+
require_relative '../data_definitions/piece'
|
|
8
|
+
require_relative '../data_definitions/square'
|
|
9
|
+
require_relative '../data_definitions/board'
|
|
10
|
+
require_relative '../data_definitions/position'
|
|
11
|
+
require_relative '../data_definitions/events'
|
|
12
|
+
require_relative '../data_definitions/primitives/colors'
|
|
13
|
+
require_relative '../data_definitions/primitives/castling_data'
|
|
14
|
+
|
|
15
|
+
module ChessEngine
|
|
16
|
+
module Game
|
|
17
|
+
# Represents the immutable state of the game at a specific point in time.
|
|
18
|
+
#
|
|
19
|
+
# Holds all the information needed to fully describe the current state of a chess game:
|
|
20
|
+
# the board layout, which player's turn it is, history, castling rights, en passant target, and more.
|
|
21
|
+
#
|
|
22
|
+
# Responsibilities:
|
|
23
|
+
# - Answer queries about the current position (through the `Game::Query` object).
|
|
24
|
+
# - Produce the next `State` by applying a valid event (`#apply_event`).
|
|
25
|
+
#
|
|
26
|
+
# Internal structure:
|
|
27
|
+
# - position: A `Position` object representing the current game position
|
|
28
|
+
# - history: A `Game::History` object representing all that happened since the creation of the originating `State`.
|
|
29
|
+
# - query: A `Game::Query` object that provides a high-level interface for interrogating the state.
|
|
30
|
+
#
|
|
31
|
+
# The design avoids mutable state — each change produces a new `State`, leaving previous states untouched.
|
|
32
|
+
# This makes reasoning about the engine easier and enables features like undo and state comparison.
|
|
33
|
+
class State
|
|
34
|
+
attr_reader :query, :position, :history
|
|
35
|
+
|
|
36
|
+
# The state at the game's start
|
|
37
|
+
def self.start
|
|
38
|
+
State.new(position: Position.start, history: History.start)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Load a new gamestate from position. Suitable for FEN.
|
|
42
|
+
def self.load(position)
|
|
43
|
+
history = History.start.with(start_position: position)
|
|
44
|
+
State.new(position: position, history: history)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Make a new `State` from an existing one.
|
|
48
|
+
# Good for computations requiring forking the state.
|
|
49
|
+
def with(position: @position, history: @history)
|
|
50
|
+
State.new(position: position, history: history)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Low-level initialization, loads all fields. Use with caution.
|
|
54
|
+
def initialize(position: Position.start, history: History.start)
|
|
55
|
+
unless position.is_a?(Position) && history.is_a?(History)
|
|
56
|
+
raise ArgumentError,
|
|
57
|
+
"One or more invalid arguments: #{position}, #{history}"
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
@position = position
|
|
61
|
+
@history = history
|
|
62
|
+
@query = Query.new(@position, @history)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Process an event to produce the next `State`
|
|
66
|
+
# Assumes the event is valid and complete.
|
|
67
|
+
def apply_event(event)
|
|
68
|
+
raise ArgumentError unless event.is_a?(Events::BaseEvent)
|
|
69
|
+
|
|
70
|
+
State.new(
|
|
71
|
+
position: advance_position(event),
|
|
72
|
+
history: advance_history(event)
|
|
73
|
+
)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
private
|
|
77
|
+
|
|
78
|
+
def advance_history(event)
|
|
79
|
+
signatures = history.position_signatures
|
|
80
|
+
signature_count = signatures.fetch(@position.signature, 0)
|
|
81
|
+
new_signatures = signatures.put(@position.signature, signature_count + 1)
|
|
82
|
+
|
|
83
|
+
history.with(moves: history.moves.add(event), position_signatures: new_signatures)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def advance_position(event)
|
|
87
|
+
Position.new(
|
|
88
|
+
board: advance_board(event),
|
|
89
|
+
current_color: @position.other_color,
|
|
90
|
+
en_passant_target: compute_en_passant(event),
|
|
91
|
+
castling_rights: compute_castling_rights(event),
|
|
92
|
+
halfmove_clock: compute_halfmove_clock(event),
|
|
93
|
+
fullmove_number: compute_fullmove_number
|
|
94
|
+
)
|
|
95
|
+
rescue InvalidEventError; raise
|
|
96
|
+
rescue InvariantViolationError => e
|
|
97
|
+
raise InvalidEventError,
|
|
98
|
+
"Invariant violation during event application: #{e.class} - #{e.message}\nEvent: #{event}"
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def advance_board(event)
|
|
102
|
+
board = @position.board
|
|
103
|
+
case event
|
|
104
|
+
in MovePieceEvent
|
|
105
|
+
advance_with_move_piece_event(board, event)
|
|
106
|
+
in EnPassantEvent => e
|
|
107
|
+
board.remove(e.captured.square).move(e.from, e.to)
|
|
108
|
+
in CastlingEvent => e
|
|
109
|
+
board.move(e.king_from, e.king_to).move(e.rook_from, e.rook_to)
|
|
110
|
+
else
|
|
111
|
+
raise InvalidEventError, "Unhandled event type: #{event.class}"
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def advance_with_move_piece_event(board, event)
|
|
116
|
+
final_piece = event.promote_to ? Piece.new(event.piece.color, event.promote_to) : event.piece
|
|
117
|
+
|
|
118
|
+
# capture if applicable
|
|
119
|
+
board = board.remove(event.captured.square) if event.captured
|
|
120
|
+
# move the piece
|
|
121
|
+
board.remove(event.from).insert(final_piece, event.to)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def compute_en_passant(event)
|
|
125
|
+
# Get the last move and ensure it was a pawn moving two steps forward
|
|
126
|
+
return unless event.is_a?(MovePieceEvent) && event.piece.type == :pawn &&
|
|
127
|
+
event.from.distance(event.to) == [0, 2]
|
|
128
|
+
|
|
129
|
+
# Return the square passed over
|
|
130
|
+
sq = Square[event.from.file, (event.from.rank + event.to.rank) / 2]
|
|
131
|
+
raise InvariantViolationError, "Invalid en passant target: #{sq}" unless sq.valid?
|
|
132
|
+
|
|
133
|
+
sq
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def compute_castling_rights(event)
|
|
137
|
+
current_color_sides = castling_sides_for_current_color(event)
|
|
138
|
+
other_color_sides = castling_sides_for_other_color(event)
|
|
139
|
+
@position.castling_rights.with(@position.current_color => current_color_sides,
|
|
140
|
+
@position.other_color => other_color_sides)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# Helpers for computing castling rights
|
|
144
|
+
def castling_sides_for_current_color(event)
|
|
145
|
+
color = @position.current_color
|
|
146
|
+
sides = @position.castling_rights.sides color
|
|
147
|
+
|
|
148
|
+
case event
|
|
149
|
+
in MovePieceEvent => e
|
|
150
|
+
if e.piece.type == :king
|
|
151
|
+
sides.with(kingside: false, queenside: false)
|
|
152
|
+
elsif e.from == CastlingData.rook_from(color, :kingside)
|
|
153
|
+
sides.with(kingside: false)
|
|
154
|
+
elsif e.from == CastlingData.rook_from(color, :queenside)
|
|
155
|
+
sides.with(queenside: false)
|
|
156
|
+
else
|
|
157
|
+
sides
|
|
158
|
+
end
|
|
159
|
+
in CastlingEvent
|
|
160
|
+
sides.with(kingside: false, queenside: false)
|
|
161
|
+
else
|
|
162
|
+
sides
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def castling_sides_for_other_color(event)
|
|
167
|
+
color = @position.other_color
|
|
168
|
+
sides = @position.castling_rights.sides color
|
|
169
|
+
|
|
170
|
+
return sides unless event.is_a?(MovePieceEvent)
|
|
171
|
+
|
|
172
|
+
captured = event.captured
|
|
173
|
+
return sides if captured.nil? || captured.piece.type != :rook
|
|
174
|
+
|
|
175
|
+
case captured.square
|
|
176
|
+
when CastlingData.rook_from(color, :kingside)
|
|
177
|
+
sides.with(kingside: false)
|
|
178
|
+
when CastlingData.rook_from(color, :queenside)
|
|
179
|
+
sides.with(queenside: false)
|
|
180
|
+
else
|
|
181
|
+
sides
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def compute_halfmove_clock(event)
|
|
186
|
+
reset_clock = (event.is_a?(MovePieceEvent) && (event.piece.type == :pawn || event.captured)) ||
|
|
187
|
+
event.is_a?(EnPassantEvent)
|
|
188
|
+
|
|
189
|
+
reset_clock ? 0 : @position.halfmove_clock + 1
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def compute_fullmove_number
|
|
193
|
+
increment = @position.current_color == :black ? 1 : 0
|
|
194
|
+
@position.fullmove_number + increment
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
end
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../data_definitions/events'
|
|
4
|
+
require_relative '../data_definitions/primitives/core_notation'
|
|
5
|
+
|
|
6
|
+
module ChessEngine
|
|
7
|
+
module Parsers
|
|
8
|
+
# A parser for ERAN, a notation made specifically for the engine.
|
|
9
|
+
# See the docs for more details.
|
|
10
|
+
class ERANParser
|
|
11
|
+
SQR = /[a-h][1-8]/i
|
|
12
|
+
MOVEMENT = /(?<from>#{SQR})((?<silent>-)|(?<capture>x))(?<to>#{SQR})/i
|
|
13
|
+
|
|
14
|
+
PIECE = /pawn|rook|bishop|knight|queen|king|[prbnqk]/i
|
|
15
|
+
PROMOTION = /queen|rook|bishop|knight|[qrbn]/i
|
|
16
|
+
|
|
17
|
+
REGULAR_MOVE = /
|
|
18
|
+
(?<piece>#{PIECE})\s+
|
|
19
|
+
(?<movement>#{MOVEMENT})
|
|
20
|
+
(?:\s+(?:->|>)(?<promotion>#{PROMOTION}))?
|
|
21
|
+
/x
|
|
22
|
+
SPECIAL_MOVE = /
|
|
23
|
+
(?:
|
|
24
|
+
(?<en_passant>ep|en-passant) |
|
|
25
|
+
(?<kingside>ck|castling-kingside) |
|
|
26
|
+
(?<queenside>cq|castling-queenside)
|
|
27
|
+
)/ix
|
|
28
|
+
|
|
29
|
+
MOVE = /
|
|
30
|
+
\A\s*
|
|
31
|
+
(?:
|
|
32
|
+
(?<regular>#{REGULAR_MOVE}) |
|
|
33
|
+
(?<special>#{SPECIAL_MOVE})
|
|
34
|
+
)
|
|
35
|
+
\s*\Z
|
|
36
|
+
/ixo
|
|
37
|
+
|
|
38
|
+
class << self
|
|
39
|
+
def call(notation, _query = nil)
|
|
40
|
+
match = MOVE.match(notation)
|
|
41
|
+
return unless match
|
|
42
|
+
|
|
43
|
+
return parse_special_move(match) if match[:special]
|
|
44
|
+
|
|
45
|
+
parse_regular_move(match)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
def parse_special_move(match)
|
|
51
|
+
if match[:en_passant]
|
|
52
|
+
EnPassantEvent[nil, nil, nil]
|
|
53
|
+
elsif match[:kingside]
|
|
54
|
+
CastlingEvent[nil, :kingside]
|
|
55
|
+
elsif match[:queenside]
|
|
56
|
+
CastlingEvent[nil, :queenside]
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def parse_regular_move(match)
|
|
61
|
+
piece = Piece[nil, str_to_piece_type(match[:piece])]
|
|
62
|
+
from = CoreNotation.str_to_square(match[:from].downcase)
|
|
63
|
+
to = CoreNotation.str_to_square(match[:to].downcase)
|
|
64
|
+
|
|
65
|
+
event = MovePieceEvent[piece, from, to]
|
|
66
|
+
event = event.capture if match[:capture]
|
|
67
|
+
if (promotion = match[:promotion])
|
|
68
|
+
event = event.promote(str_to_piece_type(promotion))
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
event
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def str_to_piece_type(str)
|
|
75
|
+
str = str.downcase
|
|
76
|
+
if Piece::TYPES.include?(str.to_sym)
|
|
77
|
+
str.to_sym
|
|
78
|
+
else
|
|
79
|
+
CoreNotation.str_to_piece(str).type
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../data_definitions/events'
|
|
4
|
+
|
|
5
|
+
module ChessEngine
|
|
6
|
+
module Parsers
|
|
7
|
+
# A parser that returns the input event unchanged.
|
|
8
|
+
# Used primarily for testing, as it bypasses actual notation parsing
|
|
9
|
+
# and assumes the input is already valid.
|
|
10
|
+
class IdentityParser
|
|
11
|
+
def self.call(notation, _game_query)
|
|
12
|
+
return nil unless notation.is_a?(Events::BaseEvent)
|
|
13
|
+
|
|
14
|
+
notation
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'eran_parser'
|
|
4
|
+
require_relative 'identity_parser'
|
|
5
|
+
|
|
6
|
+
module ChessEngine
|
|
7
|
+
# Namespace for all chess notation parsers.
|
|
8
|
+
#
|
|
9
|
+
# Parsers convert notation input into syntactically correct `Events::BaseEvent` objects.
|
|
10
|
+
# The output must accurately reflect the provided notation, but need not ensure
|
|
11
|
+
# that the move is *legally valid* within the game — legality is verified later
|
|
12
|
+
# by the engine.
|
|
13
|
+
#
|
|
14
|
+
# Each parser should implement `.call(notation, game_query)`, returning a syntactically valid event
|
|
15
|
+
# for the given notation, or `nil` if the notation cannot be parsed.
|
|
16
|
+
#
|
|
17
|
+
# A syntactically correct event is a `Events::BaseEvent` for which every provided field is of the expected type,
|
|
18
|
+
# or `nil`.
|
|
19
|
+
module Parsers
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'pathname'
|
|
4
|
+
lib_dir = Pathname.new(__FILE__).dirname.expand_path
|
|
5
|
+
|
|
6
|
+
$LOAD_PATH.unshift(lib_dir.to_s) unless $LOAD_PATH.include?(lib_dir.to_s)
|
|
7
|
+
|
|
8
|
+
# Main namespace for the engine.
|
|
9
|
+
# Contains all core logic, data definitions, parsers, and more.
|
|
10
|
+
module ChessEngine
|
|
11
|
+
# --- Main components ---
|
|
12
|
+
# Main class
|
|
13
|
+
autoload :Engine, 'chess_engine/engine'
|
|
14
|
+
|
|
15
|
+
# components
|
|
16
|
+
autoload :EventHandlers, 'chess_engine/event_handlers/init'
|
|
17
|
+
autoload :Game, 'chess_engine/game/init'
|
|
18
|
+
autoload :Parsers, 'chess_engine/parsers/init'
|
|
19
|
+
autoload :Formatters, 'chess_engine/formatters/init'
|
|
20
|
+
|
|
21
|
+
# --- Data Definitions ---
|
|
22
|
+
autoload :Piece, 'chess_engine/data_definitions/piece'
|
|
23
|
+
autoload :Square, 'chess_engine/data_definitions/square'
|
|
24
|
+
autoload :Board, 'chess_engine/data_definitions/board'
|
|
25
|
+
|
|
26
|
+
autoload :Position, 'chess_engine/data_definitions/position'
|
|
27
|
+
autoload :CastlingRights, 'chess_engine/data_definitions/components/castling_rights'
|
|
28
|
+
|
|
29
|
+
# Events
|
|
30
|
+
autoload :Events, 'chess_engine/data_definitions/events'
|
|
31
|
+
autoload :MovePieceEvent, 'chess_engine/data_definitions/events'
|
|
32
|
+
autoload :CastlingEvent, 'chess_engine/data_definitions/events'
|
|
33
|
+
autoload :EnPassantEvent, 'chess_engine/data_definitions/events'
|
|
34
|
+
|
|
35
|
+
# primitive data definitions
|
|
36
|
+
autoload :CastlingData, 'chess_engine/data_definitions/primitives/castling_data'
|
|
37
|
+
autoload :Colors, 'chess_engine/data_definitions/primitives/colors'
|
|
38
|
+
autoload :CoreNotation, 'chess_engine/data_definitions/primitives/core_notation'
|
|
39
|
+
|
|
40
|
+
# --- Errors ---
|
|
41
|
+
autoload :InvariantViolationError, 'chess_engine/errors'
|
|
42
|
+
autoload :InvalidEventError, 'chess_engine/errors'
|
|
43
|
+
autoload :BoardManipulationError, 'chess_engine/errors'
|
|
44
|
+
autoload :InvalidSquareError, 'chess_engine/errors'
|
|
45
|
+
autoload :InternalEngineError, 'chess_engine/errors'
|
|
46
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: chess_engine_rb
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- nadi726
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 2025-12-08 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: immutable-ruby
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: 0.2.0
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: 0.2.0
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: wholeable
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - "~>"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '1.4'
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '1.4'
|
|
40
|
+
description: |+
|
|
41
|
+
A modular, deterministic chess engine built around immutable objects.
|
|
42
|
+
Cleanly expresses chess concepts in code and designed for easy integration with any UI.
|
|
43
|
+
|
|
44
|
+
> ⚠️ Note: This is not a competitive chess engine like Stockfish.
|
|
45
|
+
While AI features could be added in the future, the core purpose of this project is to provide a ruby gem for cleanly representing chess in code.
|
|
46
|
+
|
|
47
|
+
email:
|
|
48
|
+
- 16650084+nadi726@users.noreply.github.com
|
|
49
|
+
executables: []
|
|
50
|
+
extensions: []
|
|
51
|
+
extra_rdoc_files: []
|
|
52
|
+
files:
|
|
53
|
+
- LICENSE
|
|
54
|
+
- README.md
|
|
55
|
+
- lib/chess_engine/data_definitions/README.md
|
|
56
|
+
- lib/chess_engine/data_definitions/board.rb
|
|
57
|
+
- lib/chess_engine/data_definitions/components/castling_rights.rb
|
|
58
|
+
- lib/chess_engine/data_definitions/components/persistent_array.rb
|
|
59
|
+
- lib/chess_engine/data_definitions/events.rb
|
|
60
|
+
- lib/chess_engine/data_definitions/piece.rb
|
|
61
|
+
- lib/chess_engine/data_definitions/position.rb
|
|
62
|
+
- lib/chess_engine/data_definitions/primitives/castling_data.rb
|
|
63
|
+
- lib/chess_engine/data_definitions/primitives/colors.rb
|
|
64
|
+
- lib/chess_engine/data_definitions/primitives/core_notation.rb
|
|
65
|
+
- lib/chess_engine/data_definitions/primitives/movement.rb
|
|
66
|
+
- lib/chess_engine/data_definitions/square.rb
|
|
67
|
+
- lib/chess_engine/engine.rb
|
|
68
|
+
- lib/chess_engine/errors.rb
|
|
69
|
+
- lib/chess_engine/event_handlers/base_event_handler.rb
|
|
70
|
+
- lib/chess_engine/event_handlers/castling_event_handler.rb
|
|
71
|
+
- lib/chess_engine/event_handlers/en_passant_event_handler.rb
|
|
72
|
+
- lib/chess_engine/event_handlers/init.rb
|
|
73
|
+
- lib/chess_engine/event_handlers/move_event_handler.rb
|
|
74
|
+
- lib/chess_engine/formatters/eran_formatters.rb
|
|
75
|
+
- lib/chess_engine/formatters/init.rb
|
|
76
|
+
- lib/chess_engine/formatters/validation.rb
|
|
77
|
+
- lib/chess_engine/game/history.rb
|
|
78
|
+
- lib/chess_engine/game/init.rb
|
|
79
|
+
- lib/chess_engine/game/legal_moves_helper.rb
|
|
80
|
+
- lib/chess_engine/game/query.rb
|
|
81
|
+
- lib/chess_engine/game/state.rb
|
|
82
|
+
- lib/chess_engine/parsers/eran_parser.rb
|
|
83
|
+
- lib/chess_engine/parsers/identity_parser.rb
|
|
84
|
+
- lib/chess_engine/parsers/init.rb
|
|
85
|
+
- lib/chess_engine_rb.rb
|
|
86
|
+
homepage: https://github.com/nadi726/ruby-chess-engine
|
|
87
|
+
licenses:
|
|
88
|
+
- MIT
|
|
89
|
+
metadata:
|
|
90
|
+
homepage_uri: https://github.com/nadi726/ruby-chess-engine
|
|
91
|
+
source_code_uri: https://github.com/nadi726/ruby-chess-engine
|
|
92
|
+
rubygems_mfa_required: 'true'
|
|
93
|
+
rdoc_options: []
|
|
94
|
+
require_paths:
|
|
95
|
+
- lib
|
|
96
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
97
|
+
requirements:
|
|
98
|
+
- - ">="
|
|
99
|
+
- !ruby/object:Gem::Version
|
|
100
|
+
version: 3.4.1
|
|
101
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
102
|
+
requirements:
|
|
103
|
+
- - ">="
|
|
104
|
+
- !ruby/object:Gem::Version
|
|
105
|
+
version: '0'
|
|
106
|
+
requirements: []
|
|
107
|
+
rubygems_version: 3.6.2
|
|
108
|
+
specification_version: 4
|
|
109
|
+
summary: A UI-agnostic, event-driven, mostly-immutable chess engine written in pure
|
|
110
|
+
Ruby.
|
|
111
|
+
test_files: []
|
|
112
|
+
...
|