sashite-ggn 0.6.0 → 0.8.0

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.
data/lib/sashite/ggn.rb CHANGED
@@ -1,323 +1,58 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'json'
4
- require 'json_schemer'
5
- require 'pathname'
6
-
7
- require_relative File.join("ggn", "ruleset")
8
- require_relative File.join("ggn", "schema")
9
- require_relative File.join("ggn", "validation_error")
3
+ require_relative "ggn/ruleset"
10
4
 
11
5
  module Sashite
12
- # General Gameplay Notation (GGN) module for parsing, validating, and working with
13
- # JSON documents that describe pseudo-legal moves in abstract strategy board games.
14
- #
15
- # GGN is a rule-agnostic format that focuses exclusively on board-to-board transformations.
16
- # It answers the fundamental question: "Can this piece, currently on this square, reach
17
- # that square?" while remaining neutral about higher-level game rules like check, ko,
18
- # repetition, or castling paths.
19
- #
20
- # = Key Features
21
- #
22
- # - **Rule-agnostic**: Works with any abstract strategy board game
23
- # - **Board-focused**: Describes only board transformations, no hand management
24
- # - **Pseudo-legal** focus: Describes basic movement constraints only
25
- # - **JSON-based**: Structured, machine-readable format
26
- # - **Validation** support: Built-in schema validation
27
- # - **Performance** optimized: Optional validation for large datasets
28
- # - **Cross-game** compatible: Supports hybrid games and variants
6
+ # General Gameplay Notation (GGN) implementation
29
7
  #
30
- # = Related Specifications
8
+ # GGN is a rule-agnostic format for describing pseudo-legal moves
9
+ # in abstract strategy board games.
31
10
  #
32
- # GGN works alongside other Sashité specifications:
33
- # - **GAN** (General Actor Notation): Unique piece identifiers
34
- # - **FEEN** (Forsyth-Edwards Enhanced Notation): Board position representation
35
- # - **PMN** (Portable Move Notation): Move sequence representation
36
- #
37
- # @author Sashité <https://sashite.com/>
38
- # @version 1.0.0
39
- # @see https://sashite.dev/documents/ggn/1.0.0/ Official GGN Specification
40
- # @see https://sashite.dev/schemas/ggn/1.0.0/schema.json JSON Schema
11
+ # @see https://sashite.dev/specs/ggn/1.0.0/
41
12
  module Ggn
42
- class << self
43
- # Loads and validates a GGN JSON file from the filesystem.
44
- #
45
- # This method provides a complete pipeline for loading GGN data:
46
- # 1. Reads the JSON file from the filesystem with proper encoding
47
- # 2. Parses the JSON content into a Ruby Hash with error handling
48
- # 3. Optionally validates the structure against the GGN JSON Schema
49
- # 4. Creates and returns a Ruleset instance for querying moves
50
- #
51
- # @param filepath [String, Pathname] Path to the GGN JSON file to load.
52
- # Supports both relative and absolute paths.
53
- # @param validate [Boolean] Whether to validate against GGN schema (default: true).
54
- # Set to false to skip validation for improved performance on large documents.
55
- # @param encoding [String] File encoding to use when reading (default: 'UTF-8').
56
- # Most GGN files should use UTF-8 encoding.
57
- #
58
- # @return [Ruleset] A Ruleset instance containing the parsed and validated GGN data.
59
- # Use this instance to query pseudo-legal moves for specific pieces and positions.
60
- #
61
- # @raise [ValidationError] If any of the following conditions occur:
62
- # - File doesn't exist or cannot be read
63
- # - File contains invalid JSON syntax
64
- # - File permissions prevent reading
65
- # - When validation is enabled: data doesn't conform to GGN schema
66
- #
67
- # @example Loading a chess piece definition with full validation
68
- # begin
69
- # piece_data = Sashite::Ggn.load_file('data/chess_pieces.json')
70
- # chess_king_source = piece_data.select('CHESS:K')
71
- # puts "Loaded chess king movement rules successfully"
72
- # rescue Sashite::Ggn::ValidationError => e
73
- # puts "Failed to load chess pieces: #{e.message}"
74
- # end
75
- #
76
- # @example Complete workflow with move evaluation
77
- # begin
78
- # piece_data = Sashite::Ggn.load_file('data/chess.json')
79
- # source = piece_data.select('CHESS:K')
80
- # destinations = source.from('e1')
81
- # engine = destinations.to('e2')
82
- #
83
- # board_state = { 'e1' => 'CHESS:K', 'e2' => nil }
84
- # transitions = engine.where(board_state, 'CHESS')
85
- # puts "King can move from e1 to e2" if transitions.any?
86
- # rescue Sashite::Ggn::ValidationError => e
87
- # puts "Failed to process move: #{e.message}"
88
- # end
89
- #
90
- # @example Loading large datasets without validation for performance
91
- # begin
92
- # # Skip validation for large files to improve loading performance
93
- # large_dataset = Sashite::Ggn.load_file('data/all_variants.json', validate: false)
94
- # puts "Loaded GGN data without validation"
95
- # rescue Sashite::Ggn::ValidationError => e
96
- # puts "Failed to load dataset: #{e.message}"
97
- # end
98
- #
99
- # @example Handling different file encodings
100
- # # Load a GGN file with specific encoding
101
- # piece_data = Sashite::Ggn.load_file('legacy_data.json', encoding: 'ISO-8859-1')
102
- #
103
- # @note Performance Considerations
104
- # For large GGN files (>1MB), consider setting validate: false to improve
105
- # loading performance. However, this comes with the risk of processing
106
- # malformed data. In production environments, validate at least once
107
- # before deploying with validation disabled.
108
- #
109
- # @note Thread Safety
110
- # This method is thread-safe for concurrent reads of different files.
111
- # However, avoid concurrent access to the same file if it might be
112
- # modified during reading.
113
- def load_file(filepath, validate: true, encoding: 'UTF-8')
114
- # Convert to Pathname for consistent file operations and better error handling
115
- file_path = normalize_filepath(filepath)
116
-
117
- # Validate file accessibility before attempting to read
118
- validate_file_access(file_path)
119
-
120
- # Parse JSON content with comprehensive error handling
121
- data = parse_json_file(file_path, encoding)
122
-
123
- # Validate against GGN schema if requested
124
- validate_schema(data, file_path) if validate
125
-
126
- # Create and return Ruleset instance
127
- Ruleset.new(data)
128
- end
129
-
130
- # Loads GGN data directly from a JSON string.
131
- #
132
- # This method is useful when you have GGN data as a string (e.g., from a
133
- # database, API response, or embedded in your application) rather than a file.
134
- #
135
- # @param json_string [String] JSON string containing GGN data
136
- # @param validate [Boolean] Whether to validate against GGN schema (default: true)
137
- #
138
- # @return [Ruleset] A Ruleset instance containing the parsed GGN data
139
- #
140
- # @raise [ValidationError] If the JSON is invalid or doesn't conform to GGN schema
141
- #
142
- # @example Loading GGN data from a string
143
- # ggn_json = '{"CHESS:P": {"e2": {"e4": [{"require": {"e3": "empty", "e4": "empty"}, "perform": {"e2": null, "e4": "CHESS:P"}}]}}}'
144
- #
145
- # begin
146
- # piece_data = Sashite::Ggn.load_string(ggn_json)
147
- # pawn_source = piece_data.select('CHESS:P')
148
- # puts "Loaded pawn with move from e2 to e4"
149
- # rescue Sashite::Ggn::ValidationError => e
150
- # puts "Invalid GGN data: #{e.message}"
151
- # end
152
- #
153
- # @example Loading from API response without validation
154
- # api_response = fetch_ggn_from_api()
155
- # piece_data = Sashite::Ggn.load_string(api_response.body, validate: false)
156
- def load_string(json_string, validate: true)
157
- # Parse JSON string with error handling
158
- begin
159
- data = ::JSON.parse(json_string)
160
- rescue ::JSON::ParserError => e
161
- raise ValidationError, "Invalid JSON string: #{e.message}"
162
- end
163
-
164
- # Validate against GGN schema if requested
165
- validate_schema(data, "<string>") if validate
166
-
167
- # Create and return Ruleset instance
168
- Ruleset.new(data)
169
- end
170
-
171
- # Loads GGN data from a Ruby Hash.
172
- #
173
- # This method is useful when you already have parsed JSON data as a Hash
174
- # and want to create a GGN Ruleset instance with optional validation.
175
- #
176
- # @param data [Hash] Ruby Hash containing GGN data structure
177
- # @param validate [Boolean] Whether to validate against GGN schema (default: true)
178
- #
179
- # @return [Ruleset] A Ruleset instance containing the GGN data
180
- #
181
- # @raise [ValidationError] If the data doesn't conform to GGN schema (when validation enabled)
182
- #
183
- # @example Creating from existing Hash data
184
- # ggn_data = {
185
- # "CHESS:K" => {
186
- # "e1" => {
187
- # "e2" => [{ "require" => { "e2" => "empty" }, "perform" => { "e1" => nil, "e2" => "CHESS:K" } }],
188
- # "f1" => [{ "require" => { "f1" => "empty" }, "perform" => { "e1" => nil, "f1" => "CHESS:K" } }]
189
- # }
190
- # }
191
- # }
192
- #
193
- # piece_data = Sashite::Ggn.load_hash(ggn_data)
194
- # chess_king = piece_data.select('CHESS:K')
195
- def load_hash(data, validate: true)
196
- unless data.is_a?(Hash)
197
- raise ValidationError, "Expected Hash, got #{data.class}"
198
- end
199
-
200
- # Validate against GGN schema if requested
201
- validate_schema(data, "<hash>") if validate
202
-
203
- # Create and return Ruleset instance
204
- Ruleset.new(data)
205
- end
206
-
207
- # Validates a data structure against the GGN JSON Schema.
208
- #
209
- # This method can be used independently to validate GGN data without
210
- # creating a Ruleset instance. Useful for pre-validation or testing.
211
- #
212
- # @param data [Hash] The data structure to validate
213
- # @param context [String] Context information for error messages (default: "<data>")
214
- #
215
- # @return [true] If validation passes
216
- #
217
- # @raise [ValidationError] If validation fails with detailed error information
218
- #
219
- # @example Validating data before processing
220
- # begin
221
- # Sashite::Ggn.validate!(my_data)
222
- # puts "Data is valid GGN format"
223
- # rescue Sashite::Ggn::ValidationError => e
224
- # puts "Validation failed: #{e.message}"
225
- # end
226
- def validate!(data, context: "<data>")
227
- validate_schema(data, context)
228
- true
229
- end
230
-
231
- # Checks if a data structure is valid GGN format.
232
- #
233
- # @param data [Hash] The data structure to validate
234
- #
235
- # @return [Boolean] true if valid, false otherwise
236
- #
237
- # @example Checking validity without raising exceptions
238
- # if Sashite::Ggn.valid?(my_data)
239
- # puts "Data is valid"
240
- # else
241
- # puts "Data is invalid"
242
- # end
243
- def valid?(data)
244
- schemer = ::JSONSchemer.schema(Schema)
245
- schemer.valid?(data)
246
- end
247
-
248
- # Returns detailed validation errors for a data structure.
249
- #
250
- # @param data [Hash] The data structure to validate
251
- #
252
- # @return [Array<String>] Array of validation error messages (empty if valid)
253
- #
254
- # @example Getting detailed validation errors
255
- # errors = Sashite::Ggn.validation_errors(invalid_data)
256
- # if errors.any?
257
- # puts "Validation errors found:"
258
- # errors.each { |error| puts " - #{error}" }
259
- # end
260
- def validation_errors(data)
261
- schemer = ::JSONSchemer.schema(Schema)
262
- schemer.validate(data).map(&:to_s)
263
- end
264
-
265
- private
266
-
267
- # Normalizes filepath input to Pathname instance
268
- def normalize_filepath(filepath)
269
- case filepath
270
- when ::Pathname
271
- filepath
272
- when String
273
- ::Pathname.new(filepath)
274
- else
275
- raise ValidationError, "Invalid filepath type: #{filepath.class}. Expected String or Pathname."
276
- end
277
- end
278
-
279
- # Validates that a file exists and is readable
280
- def validate_file_access(file_path)
281
- unless file_path.exist?
282
- raise ValidationError, "File not found: #{file_path}"
283
- end
284
-
285
- unless file_path.readable?
286
- raise ValidationError, "File not readable: #{file_path}"
287
- end
288
-
289
- unless file_path.file?
290
- raise ValidationError, "Path is not a file: #{file_path}"
291
- end
292
- end
293
-
294
- # Parses JSON file with proper error handling and encoding
295
- def parse_json_file(file_path, encoding)
296
- # Read file with specified encoding
297
- content = file_path.read(encoding: encoding)
298
-
299
- # Parse JSON content
300
- ::JSON.parse(content)
301
- rescue ::JSON::ParserError => e
302
- raise ValidationError, "Invalid JSON in file #{file_path}: #{e.message}"
303
- rescue ::Encoding::UndefinedConversionError => e
304
- raise ValidationError, "Encoding error in file #{file_path}: #{e.message}. Try a different encoding."
305
- rescue ::SystemCallError => e
306
- raise ValidationError, "Failed to read file #{file_path}: #{e.message}"
307
- end
308
-
309
- # Validates data against GGN schema with detailed error reporting
310
- def validate_schema(data, context)
311
- schemer = ::JSONSchemer.schema(Schema)
312
-
313
- return if schemer.valid?(data)
314
-
315
- # Collect all validation errors for comprehensive feedback
316
- errors = schemer.validate(data).map(&:to_s)
317
- error_summary = errors.size == 1 ? "1 validation error" : "#{errors.size} validation errors"
13
+ # Parse GGN data structure into an immutable Ruleset
14
+ #
15
+ # @param data [Hash] GGN data structure conforming to specification
16
+ # @return [Ruleset] Immutable ruleset object
17
+ # @raise [ArgumentError, TypeError] If data structure is invalid
18
+ #
19
+ # @example Parse GGN data
20
+ # ruleset = Sashite::Ggn.parse({
21
+ # "C:P" => {
22
+ # "e2" => {
23
+ # "e4" => [
24
+ # {
25
+ # "must" => { "e3" => "empty", "e4" => "empty" },
26
+ # "deny" => {},
27
+ # "diff" => {
28
+ # "board" => { "e2" => nil, "e4" => "C:P" },
29
+ # "toggle" => true
30
+ # }
31
+ # }
32
+ # ]
33
+ # }
34
+ # }
35
+ # })
36
+ def self.parse(data)
37
+ Ruleset.new(data)
38
+ end
318
39
 
319
- raise ValidationError, "Invalid GGN data in #{context}: #{error_summary}: #{errors.join('; ')}"
320
- end
40
+ # Validate GGN data structure against specification
41
+ #
42
+ # @param data [Hash] Data structure to validate
43
+ # @return [Boolean] True if valid, false otherwise
44
+ #
45
+ # @note Rescues both ArgumentError (invalid structure) and TypeError (wrong type)
46
+ #
47
+ # @example Validate GGN data
48
+ # Sashite::Ggn.valid?(ggn_data) # => true
49
+ # Sashite::Ggn.valid?("invalid") # => false (TypeError)
50
+ # Sashite::Ggn.valid?(nil) # => false (TypeError)
51
+ def self.valid?(data)
52
+ parse(data)
53
+ true
54
+ rescue ::ArgumentError, ::TypeError
55
+ false
321
56
  end
322
57
  end
323
58
  end
data/lib/sashite-ggn.rb CHANGED
@@ -1,126 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Sashité - Abstract Strategy Board Games Notation Library
4
- #
5
- # This library provides a comprehensive implementation of the General Gameplay Notation (GGN)
6
- # specification, which is a rule-agnostic, JSON-based format for describing pseudo-legal
7
- # moves in abstract strategy board games.
8
- #
9
- # GGN focuses exclusively on board-to-board transformations: pieces moving, capturing,
10
- # or transforming on the game board. Hand management, drops, and captures-to-hand are
11
- # outside the scope of this specification.
12
- #
13
- # GGN works alongside other Sashité specifications:
14
- # - GAN (General Actor Notation): Unique piece identifiers
15
- # - FEEN (Forsyth-Edwards Enhanced Notation): Board position representation
16
- # - PMN (Portable Move Notation): Move sequence representation
17
- #
18
- # @author Sashité <https://sashite.com/>
19
- # @version 1.0.0
20
- # @see https://sashite.dev/documents/ggn/1.0.0/ GGN Specification
21
- # @see https://github.com/sashite/ggn.rb Official Ruby implementation
22
- #
23
- # @example Basic usage with a chess pawn double move
24
- # # Load GGN data from file
25
- # require "sashite/ggn"
26
- #
27
- # piece_data = Sashite::Ggn.load_file("chess_moves.json")
28
- # engine = piece_data.select("CHESS:P").from("e2").to("e4")
29
- #
30
- # # Check if the move is valid given current board state
31
- # board_state = {
32
- # "e2" => "CHESS:P", # White pawn on e2
33
- # "e3" => nil, # Empty square
34
- # "e4" => nil # Empty square
35
- # }
36
- #
37
- # transitions = engine.where(board_state, "CHESS")
38
- #
39
- # if transitions.any?
40
- # transition = transitions.first
41
- # puts "Move is valid!"
42
- # puts "Board changes: #{transition.diff}"
43
- # # => { "e2" => nil, "e4" => "CHESS:P" }
44
- # else
45
- # puts "Move is not valid under current conditions"
46
- # end
47
- #
48
- # @example Piece promotion with multiple variants
49
- # # Chess pawn promotion offers multiple choices
50
- # piece_data = Sashite::Ggn.load_file("chess_moves.json")
51
- # engine = piece_data.select("CHESS:P").from("e7").to("e8")
52
- #
53
- # # Board with pawn ready to promote
54
- # board_state = {
55
- # "e7" => "CHESS:P", # White pawn on 7th rank
56
- # "e8" => nil # Empty promotion square
57
- # }
58
- #
59
- # transitions = engine.where(board_state, "CHESS")
60
- #
61
- # transitions.each_with_index do |transition, i|
62
- # promoted_piece = transition.diff["e8"]
63
- # puts "Promotion choice #{i + 1}: #{promoted_piece}"
64
- # end
65
- # # Output: CHESS:Q, CHESS:R, CHESS:B, CHESS:N
66
- #
67
- # @example Complex multi-square moves like castling
68
- # # Castling involves both king and rook movement
69
- # piece_data = Sashite::Ggn.load_file("chess_moves.json")
70
- # engine = piece_data.select("CHESS:K").from("e1").to("g1")
71
- #
72
- # # Board state allowing kingside castling
73
- # board_state = {
74
- # "e1" => "CHESS:K", # King on starting square
75
- # "f1" => nil, # Empty square
76
- # "g1" => nil, # Empty destination
77
- # "h1" => "CHESS:R" # Rook on starting square
78
- # }
79
- #
80
- # transitions = engine.where(board_state, "CHESS")
81
- #
82
- # if transitions.any?
83
- # transition = transitions.first
84
- # puts "Castling is possible!"
85
- # puts "Final position: #{transition.diff}"
86
- # # => { "e1" => nil, "f1" => "CHESS:R", "g1" => "CHESS:K", "h1" => nil }
87
- # end
88
- #
89
- # @example Loading GGN data from different sources
90
- # # From file
91
- # piece_data = Sashite::Ggn.load_file("moves.json")
92
- #
93
- # # From JSON string
94
- # json_string = '{"CHESS:K": {"e1": {"e2": [{"perform": {"e1": null, "e2": "CHESS:K"}}]}}}'
95
- # piece_data = Sashite::Ggn.load_string(json_string)
96
- #
97
- # # From Hash
98
- # ggn_hash = { "CHESS:K" => { "e1" => { "e2" => [{ "perform" => { "e1" => nil, "e2" => "CHESS:K" } }] } } }
99
- # piece_data = Sashite::Ggn.load_hash(ggn_hash)
100
- #
101
- # @example Generating all possible moves
102
- # # Get all pseudo-legal moves for the current position
103
- # board_state = {
104
- # "e1" => "CHESS:K", "d1" => "CHESS:Q", "a1" => "CHESS:R",
105
- # "e2" => "CHESS:P", "d2" => "CHESS:P"
106
- # }
3
+ require_relative "sashite/ggn"
4
+
5
+ # Sashité namespace for board game notation libraries
107
6
  #
108
- # all_moves = piece_data.pseudo_legal_transitions(board_state, "CHESS")
7
+ # Sashité provides a collection of libraries for representing and manipulating
8
+ # board game concepts according to the Sashité Protocol specifications.
109
9
  #
110
- # all_moves.each do |actor, origin, target, transitions|
111
- # puts "#{actor}: #{origin} #{target} (#{transitions.size} variants)"
112
- # end
10
+ # @see https://sashite.dev/protocol/ Sashité Protocol
11
+ # @see https://sashite.dev/specs/ Sashité Specifications
12
+ # @author Sashité
113
13
  module Sashite
114
- # Base namespace for all Sashité notation libraries.
115
- #
116
- # Sashité provides a comprehensive suite of specifications and implementations
117
- # for representing abstract strategy board games in a rule-agnostic manner.
118
- # This allows for unified game engines, cross-game analysis, and hybrid
119
- # game variants.
120
- #
121
- # @see https://sashite.com/ Official Sashité website
122
- # @see https://sashite.dev/ Developer documentation and specifications
123
14
  end
124
-
125
- # Load the main GGN implementation
126
- require_relative "sashite/ggn"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sashite-ggn
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cyril Kato
@@ -10,25 +10,109 @@ cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
- name: json_schemer
13
+ name: sashite-cell
14
14
  requirement: !ruby/object:Gem::Requirement
15
15
  requirements:
16
16
  - - "~>"
17
17
  - !ruby/object:Gem::Version
18
- version: 2.4.0
18
+ version: '2.0'
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - "~>"
24
24
  - !ruby/object:Gem::Version
25
- version: 2.4.0
26
- description: A Ruby implementation of the General Gameplay Notation (GGN) specification.
27
- GGN is a rule-agnostic, JSON-based format for describing pseudo-legal board-to-board
28
- transformations in abstract strategy board games. This library provides parsing,
29
- validation, and evaluation capabilities for GGN documents, focusing exclusively
30
- on piece movements, captures, and transformations on the game board. Supports Chess,
31
- Shogi, Xiangqi, and custom variants without hand management or piece drops.
25
+ version: '2.0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: sashite-epin
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '1.1'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '1.1'
40
+ - !ruby/object:Gem::Dependency
41
+ name: sashite-feen
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '0.3'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '0.3'
54
+ - !ruby/object:Gem::Dependency
55
+ name: sashite-hand
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '1.0'
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '1.0'
68
+ - !ruby/object:Gem::Dependency
69
+ name: sashite-lcn
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '0.1'
75
+ type: :runtime
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '0.1'
82
+ - !ruby/object:Gem::Dependency
83
+ name: sashite-qpi
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '1.0'
89
+ type: :runtime
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '1.0'
96
+ - !ruby/object:Gem::Dependency
97
+ name: sashite-stn
98
+ requirement: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: '1.0'
103
+ type: :runtime
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '1.0'
110
+ description: A pure functional Ruby implementation of the General Gameplay Notation
111
+ (GGN) specification v1.0.0. Provides a movement possibility oracle for evaluating
112
+ pseudo-legal moves in abstract strategy board games. Features include hierarchical
113
+ move navigation (piece → source → destination → transitions), pre-condition evaluation
114
+ (must/deny), and state transition support via STN format. Works with Chess, Shogi,
115
+ Xiangqi, and custom variants.
32
116
  email: contact@cyril.email
33
117
  executables: []
34
118
  extensions: []
@@ -38,14 +122,10 @@ files:
38
122
  - README.md
39
123
  - lib/sashite-ggn.rb
40
124
  - lib/sashite/ggn.rb
41
- - lib/sashite/ggn/move_validator.rb
42
125
  - lib/sashite/ggn/ruleset.rb
43
126
  - lib/sashite/ggn/ruleset/source.rb
44
127
  - lib/sashite/ggn/ruleset/source/destination.rb
45
128
  - lib/sashite/ggn/ruleset/source/destination/engine.rb
46
- - lib/sashite/ggn/ruleset/source/destination/engine/transition.rb
47
- - lib/sashite/ggn/schema.rb
48
- - lib/sashite/ggn/validation_error.rb
49
129
  homepage: https://github.com/sashite/ggn.rb
50
130
  licenses:
51
131
  - MIT
@@ -54,7 +134,7 @@ metadata:
54
134
  documentation_uri: https://rubydoc.info/github/sashite/ggn.rb/main
55
135
  homepage_uri: https://github.com/sashite/ggn.rb
56
136
  source_code_uri: https://github.com/sashite/ggn.rb
57
- specification_uri: https://sashite.dev/documents/ggn/1.0.0/
137
+ specification_uri: https://sashite.dev/specs/ggn/1.0.0/
58
138
  rubygems_mfa_required: 'true'
59
139
  rdoc_options: []
60
140
  require_paths:
@@ -72,5 +152,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
72
152
  requirements: []
73
153
  rubygems_version: 3.6.9
74
154
  specification_version: 4
75
- summary: General Gameplay Notation (GGN) library for board-to-board game transformations
155
+ summary: General Gameplay Notation (GGN) - movement possibilities for board games
76
156
  test_files: []