sashite-ggn 0.7.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.
- checksums.yaml +4 -4
- data/README.md +300 -562
- data/lib/sashite/ggn/ruleset/source/destination/engine.rb +120 -309
- data/lib/sashite/ggn/ruleset/source/destination.rb +46 -84
- data/lib/sashite/ggn/ruleset/source.rb +40 -73
- data/lib/sashite/ggn/ruleset.rb +183 -403
- data/lib/sashite/ggn.rb +47 -334
- data/lib/sashite-ggn.rb +8 -120
- metadata +96 -20
- data/lib/sashite/ggn/move_validator.rb +0 -208
- data/lib/sashite/ggn/ruleset/source/destination/engine/transition.rb +0 -81
- data/lib/sashite/ggn/schema.rb +0 -171
- data/lib/sashite/ggn/validation_error.rb +0 -56
data/lib/sashite/ggn.rb
CHANGED
@@ -1,345 +1,58 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
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)
|
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 and logical consistency checks
|
27
|
-
# - **Performance** optimized: Optional validation for large datasets
|
28
|
-
# - **Cross-game** compatible: Supports hybrid games and variants
|
29
|
-
#
|
30
|
-
# = Validation Levels
|
31
|
-
#
|
32
|
-
# When `validate: true` (default), performs:
|
33
|
-
# - JSON Schema validation against GGN specification
|
34
|
-
# - Logical contradiction detection in require/prevent conditions
|
35
|
-
# - Implicit requirement duplication detection
|
36
|
-
#
|
37
|
-
# When `validate: false`, skips all validations for maximum performance.
|
38
|
-
#
|
39
|
-
# = Related Specifications
|
6
|
+
# General Gameplay Notation (GGN) implementation
|
40
7
|
#
|
41
|
-
# GGN
|
42
|
-
#
|
43
|
-
# - **FEEN** (Forsyth-Edwards Enhanced Notation): Board position representation
|
44
|
-
# - **PMN** (Portable Move Notation): Move sequence representation
|
8
|
+
# GGN is a rule-agnostic format for describing pseudo-legal moves
|
9
|
+
# in abstract strategy board games.
|
45
10
|
#
|
46
|
-
# @
|
47
|
-
# @version 1.0.0
|
48
|
-
# @see https://sashite.dev/documents/ggn/1.0.0/ Official GGN Specification
|
49
|
-
# @see https://sashite.dev/schemas/ggn/1.0.0/schema.json JSON Schema
|
11
|
+
# @see https://sashite.dev/specs/ggn/1.0.0/
|
50
12
|
module Ggn
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
# - When validation is enabled: logical contradictions or implicit duplications found
|
78
|
-
#
|
79
|
-
# @example Loading a chess piece definition with full validation
|
80
|
-
# begin
|
81
|
-
# piece_data = Sashite::Ggn.load_file('data/chess_pieces.json')
|
82
|
-
# chess_king_source = piece_data.select('CHESS:K')
|
83
|
-
# puts "Loaded chess king movement rules successfully"
|
84
|
-
# rescue Sashite::Ggn::ValidationError => e
|
85
|
-
# puts "Failed to load chess pieces: #{e.message}"
|
86
|
-
# end
|
87
|
-
#
|
88
|
-
# @example Complete workflow with move evaluation
|
89
|
-
# begin
|
90
|
-
# piece_data = Sashite::Ggn.load_file('data/chess.json')
|
91
|
-
# source = piece_data.select('CHESS:K')
|
92
|
-
# destinations = source.from('e1')
|
93
|
-
# engine = destinations.to('e2')
|
94
|
-
#
|
95
|
-
# board_state = { 'e1' => 'CHESS:K', 'e2' => nil }
|
96
|
-
# transitions = engine.where(board_state, 'CHESS')
|
97
|
-
# puts "King can move from e1 to e2" if transitions.any?
|
98
|
-
# rescue Sashite::Ggn::ValidationError => e
|
99
|
-
# puts "Failed to process move: #{e.message}"
|
100
|
-
# end
|
101
|
-
#
|
102
|
-
# @example Loading large datasets without validation for performance
|
103
|
-
# begin
|
104
|
-
# # Skip all validations for large files to improve loading performance
|
105
|
-
# large_dataset = Sashite::Ggn.load_file('data/all_variants.json', validate: false)
|
106
|
-
# puts "Loaded GGN data without validation"
|
107
|
-
# rescue Sashite::Ggn::ValidationError => e
|
108
|
-
# puts "Failed to load dataset: #{e.message}"
|
109
|
-
# end
|
110
|
-
#
|
111
|
-
# @example Handling different file encodings
|
112
|
-
# # Load a GGN file with specific encoding
|
113
|
-
# piece_data = Sashite::Ggn.load_file('legacy_data.json', encoding: 'ISO-8859-1')
|
114
|
-
#
|
115
|
-
# @note Performance Considerations
|
116
|
-
# For large GGN files (>1MB), consider setting validate: false to improve
|
117
|
-
# loading performance. However, this comes with the risk of processing
|
118
|
-
# malformed data. In production environments, validate at least once
|
119
|
-
# before deploying with validation disabled.
|
120
|
-
#
|
121
|
-
# @note Thread Safety
|
122
|
-
# This method is thread-safe for concurrent reads of different files.
|
123
|
-
# However, avoid concurrent access to the same file if it might be
|
124
|
-
# modified during reading.
|
125
|
-
def load_file(filepath, validate: true, encoding: 'UTF-8')
|
126
|
-
# Convert to Pathname for consistent file operations and better error handling
|
127
|
-
file_path = normalize_filepath(filepath)
|
128
|
-
|
129
|
-
# Validate file accessibility before attempting to read
|
130
|
-
validate_file_access(file_path)
|
131
|
-
|
132
|
-
# Parse JSON content with comprehensive error handling
|
133
|
-
data = parse_json_file(file_path, encoding)
|
134
|
-
|
135
|
-
# Validate against GGN schema if requested
|
136
|
-
validate_schema(data, file_path) if validate
|
137
|
-
|
138
|
-
# Create and return Ruleset instance with validation option
|
139
|
-
Ruleset.new(data, validate: validate)
|
140
|
-
end
|
141
|
-
|
142
|
-
# Loads GGN data directly from a JSON string.
|
143
|
-
#
|
144
|
-
# This method is useful when you have GGN data as a string (e.g., from a
|
145
|
-
# database, API response, or embedded in your application) rather than a file.
|
146
|
-
#
|
147
|
-
# @param json_string [String] JSON string containing GGN data
|
148
|
-
# @param validate [Boolean] Whether to perform all validations (default: true).
|
149
|
-
# When false, skips JSON schema validation AND internal logical validations.
|
150
|
-
#
|
151
|
-
# @return [Ruleset] A Ruleset instance containing the parsed GGN data
|
152
|
-
#
|
153
|
-
# @raise [ValidationError] If the JSON is invalid or doesn't conform to GGN schema
|
154
|
-
#
|
155
|
-
# @example Loading GGN data from a string
|
156
|
-
# ggn_json = '{"CHESS:P": {"e2": {"e4": [{"require": {"e3": "empty", "e4": "empty"}, "perform": {"e2": null, "e4": "CHESS:P"}}]}}}'
|
157
|
-
#
|
158
|
-
# begin
|
159
|
-
# piece_data = Sashite::Ggn.load_string(ggn_json)
|
160
|
-
# pawn_source = piece_data.select('CHESS:P')
|
161
|
-
# puts "Loaded pawn with move from e2 to e4"
|
162
|
-
# rescue Sashite::Ggn::ValidationError => e
|
163
|
-
# puts "Invalid GGN data: #{e.message}"
|
164
|
-
# end
|
165
|
-
#
|
166
|
-
# @example Loading from API response without validation
|
167
|
-
# api_response = fetch_ggn_from_api()
|
168
|
-
# piece_data = Sashite::Ggn.load_string(api_response.body, validate: false)
|
169
|
-
def load_string(json_string, validate: true)
|
170
|
-
# Parse JSON string with error handling
|
171
|
-
begin
|
172
|
-
data = ::JSON.parse(json_string)
|
173
|
-
rescue ::JSON::ParserError => e
|
174
|
-
raise ValidationError, "Invalid JSON string: #{e.message}"
|
175
|
-
end
|
176
|
-
|
177
|
-
# Validate against GGN schema if requested
|
178
|
-
validate_schema(data, "<string>") if validate
|
179
|
-
|
180
|
-
# Create and return Ruleset instance with validation option
|
181
|
-
Ruleset.new(data, validate: validate)
|
182
|
-
end
|
183
|
-
|
184
|
-
# Loads GGN data from a Ruby Hash.
|
185
|
-
#
|
186
|
-
# This method is useful when you already have parsed JSON data as a Hash
|
187
|
-
# and want to create a GGN Ruleset instance with optional validation.
|
188
|
-
#
|
189
|
-
# @param data [Hash] Ruby Hash containing GGN data structure
|
190
|
-
# @param validate [Boolean] Whether to perform all validations (default: true).
|
191
|
-
# When false, skips JSON schema validation AND internal logical validations.
|
192
|
-
#
|
193
|
-
# @return [Ruleset] A Ruleset instance containing the GGN data
|
194
|
-
#
|
195
|
-
# @raise [ValidationError] If the data doesn't conform to GGN schema (when validation enabled)
|
196
|
-
#
|
197
|
-
# @example Creating from existing Hash data
|
198
|
-
# ggn_data = {
|
199
|
-
# "CHESS:K" => {
|
200
|
-
# "e1" => {
|
201
|
-
# "e2" => [{ "require" => { "e2" => "empty" }, "perform" => { "e1" => nil, "e2" => "CHESS:K" } }],
|
202
|
-
# "f1" => [{ "require" => { "f1" => "empty" }, "perform" => { "e1" => nil, "f1" => "CHESS:K" } }]
|
203
|
-
# }
|
204
|
-
# }
|
205
|
-
# }
|
206
|
-
#
|
207
|
-
# piece_data = Sashite::Ggn.load_hash(ggn_data)
|
208
|
-
# chess_king = piece_data.select('CHESS:K')
|
209
|
-
def load_hash(data, validate: true)
|
210
|
-
unless data.is_a?(Hash)
|
211
|
-
raise ValidationError, "Expected Hash, got #{data.class}"
|
212
|
-
end
|
213
|
-
|
214
|
-
# Validate against GGN schema if requested
|
215
|
-
validate_schema(data, "<hash>") if validate
|
216
|
-
|
217
|
-
# Create and return Ruleset instance with validation option
|
218
|
-
Ruleset.new(data, validate: validate)
|
219
|
-
end
|
220
|
-
|
221
|
-
# Validates a data structure against the GGN JSON Schema.
|
222
|
-
#
|
223
|
-
# This method can be used independently to validate GGN data without
|
224
|
-
# creating a Ruleset instance. Useful for pre-validation or testing.
|
225
|
-
# Note: This only performs JSON Schema validation, not the internal
|
226
|
-
# logical consistency checks that Ruleset.new performs.
|
227
|
-
#
|
228
|
-
# @param data [Hash] The data structure to validate
|
229
|
-
# @param context [String] Context information for error messages (default: "<data>")
|
230
|
-
#
|
231
|
-
# @return [true] If validation passes
|
232
|
-
#
|
233
|
-
# @raise [ValidationError] If validation fails with detailed error information
|
234
|
-
#
|
235
|
-
# @example Validating data before processing
|
236
|
-
# begin
|
237
|
-
# Sashite::Ggn.validate!(my_data)
|
238
|
-
# puts "Data is valid GGN format"
|
239
|
-
# rescue Sashite::Ggn::ValidationError => e
|
240
|
-
# puts "Validation failed: #{e.message}"
|
241
|
-
# end
|
242
|
-
def validate!(data, context: "<data>")
|
243
|
-
validate_schema(data, context)
|
244
|
-
true
|
245
|
-
end
|
246
|
-
|
247
|
-
# Checks if a data structure is valid GGN format.
|
248
|
-
#
|
249
|
-
# Note: This only performs JSON Schema validation, not the internal
|
250
|
-
# logical consistency checks that Ruleset.new performs.
|
251
|
-
#
|
252
|
-
# @param data [Hash] The data structure to validate
|
253
|
-
#
|
254
|
-
# @return [Boolean] true if valid, false otherwise
|
255
|
-
#
|
256
|
-
# @example Checking validity without raising exceptions
|
257
|
-
# if Sashite::Ggn.valid?(my_data)
|
258
|
-
# puts "Data is valid"
|
259
|
-
# else
|
260
|
-
# puts "Data is invalid"
|
261
|
-
# end
|
262
|
-
def valid?(data)
|
263
|
-
schemer = ::JSONSchemer.schema(Schema)
|
264
|
-
schemer.valid?(data)
|
265
|
-
end
|
266
|
-
|
267
|
-
# Returns detailed validation errors for a data structure.
|
268
|
-
#
|
269
|
-
# Note: This only performs JSON Schema validation, not the internal
|
270
|
-
# logical consistency checks that Ruleset.new performs.
|
271
|
-
#
|
272
|
-
# @param data [Hash] The data structure to validate
|
273
|
-
#
|
274
|
-
# @return [Array<String>] Array of validation error messages (empty if valid)
|
275
|
-
#
|
276
|
-
# @example Getting detailed validation errors
|
277
|
-
# errors = Sashite::Ggn.validation_errors(invalid_data)
|
278
|
-
# if errors.any?
|
279
|
-
# puts "Validation errors found:"
|
280
|
-
# errors.each { |error| puts " - #{error}" }
|
281
|
-
# end
|
282
|
-
def validation_errors(data)
|
283
|
-
schemer = ::JSONSchemer.schema(Schema)
|
284
|
-
schemer.validate(data).map(&:to_s)
|
285
|
-
end
|
286
|
-
|
287
|
-
private
|
288
|
-
|
289
|
-
# Normalizes filepath input to Pathname instance
|
290
|
-
def normalize_filepath(filepath)
|
291
|
-
case filepath
|
292
|
-
when ::Pathname
|
293
|
-
filepath
|
294
|
-
when String
|
295
|
-
::Pathname.new(filepath)
|
296
|
-
else
|
297
|
-
raise ValidationError, "Invalid filepath type: #{filepath.class}. Expected String or Pathname."
|
298
|
-
end
|
299
|
-
end
|
300
|
-
|
301
|
-
# Validates that a file exists and is readable
|
302
|
-
def validate_file_access(file_path)
|
303
|
-
unless file_path.exist?
|
304
|
-
raise ValidationError, "File not found: #{file_path}"
|
305
|
-
end
|
306
|
-
|
307
|
-
unless file_path.readable?
|
308
|
-
raise ValidationError, "File not readable: #{file_path}"
|
309
|
-
end
|
310
|
-
|
311
|
-
unless file_path.file?
|
312
|
-
raise ValidationError, "Path is not a file: #{file_path}"
|
313
|
-
end
|
314
|
-
end
|
315
|
-
|
316
|
-
# Parses JSON file with proper error handling and encoding
|
317
|
-
def parse_json_file(file_path, encoding)
|
318
|
-
# Read file with specified encoding
|
319
|
-
content = file_path.read(encoding: encoding)
|
320
|
-
|
321
|
-
# Parse JSON content
|
322
|
-
::JSON.parse(content)
|
323
|
-
rescue ::JSON::ParserError => e
|
324
|
-
raise ValidationError, "Invalid JSON in file #{file_path}: #{e.message}"
|
325
|
-
rescue ::Encoding::UndefinedConversionError => e
|
326
|
-
raise ValidationError, "Encoding error in file #{file_path}: #{e.message}. Try a different encoding."
|
327
|
-
rescue ::SystemCallError => e
|
328
|
-
raise ValidationError, "Failed to read file #{file_path}: #{e.message}"
|
329
|
-
end
|
330
|
-
|
331
|
-
# Validates data against GGN schema with detailed error reporting
|
332
|
-
def validate_schema(data, context)
|
333
|
-
schemer = ::JSONSchemer.schema(Schema)
|
334
|
-
|
335
|
-
return if schemer.valid?(data)
|
336
|
-
|
337
|
-
# Collect all validation errors for comprehensive feedback
|
338
|
-
errors = schemer.validate(data).map(&:to_s)
|
339
|
-
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
|
340
39
|
|
341
|
-
|
342
|
-
|
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
|
343
56
|
end
|
344
57
|
end
|
345
58
|
end
|
data/lib/sashite-ggn.rb
CHANGED
@@ -1,126 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
#
|
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
|
-
#
|
7
|
+
# Sashité provides a collection of libraries for representing and manipulating
|
8
|
+
# board game concepts according to the Sashité Protocol specifications.
|
109
9
|
#
|
110
|
-
#
|
111
|
-
#
|
112
|
-
#
|
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"
|