sashite-ggn 0.2.0 → 0.5.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 +5 -5
- data/LICENSE.md +17 -18
- data/README.md +115 -28
- data/lib/sashite/ggn/move_validator.rb +180 -0
- data/lib/sashite/ggn/ruleset/source/destination/engine/transition.rb +90 -0
- data/lib/sashite/ggn/ruleset/source/destination/engine.rb +454 -0
- data/lib/sashite/ggn/ruleset/source/destination.rb +65 -0
- data/lib/sashite/ggn/ruleset/source.rb +71 -0
- data/lib/sashite/ggn/ruleset.rb +371 -0
- data/lib/sashite/ggn/schema.rb +152 -0
- data/lib/sashite/ggn/validation_error.rb +31 -0
- data/lib/sashite/ggn.rb +317 -5
- data/lib/sashite-ggn.rb +112 -1
- metadata +32 -82
- data/.gitignore +0 -22
- data/.ruby-version +0 -1
- data/.travis.yml +0 -3
- data/Gemfile +0 -2
- data/Rakefile +0 -7
- data/VERSION.semver +0 -1
- data/lib/sashite/ggn/ability.rb +0 -11
- data/lib/sashite/ggn/gameplay.rb +0 -9
- data/lib/sashite/ggn/object.rb +0 -9
- data/lib/sashite/ggn/pattern.rb +0 -9
- data/lib/sashite/ggn/square.rb +0 -7
- data/lib/sashite/ggn/state.rb +0 -7
- data/lib/sashite/ggn/subject.rb +0 -9
- data/lib/sashite/ggn/verb.rb +0 -7
- data/sashite-ggn.gemspec +0 -19
- data/test/_test_helper.rb +0 -2
- data/test/test_ggn.rb +0 -15
- data/test/test_ggn_ability.rb +0 -41
- data/test/test_ggn_gameplay.rb +0 -17
- data/test/test_ggn_object.rb +0 -41
- data/test/test_ggn_pattern.rb +0 -17
- data/test/test_ggn_square.rb +0 -41
- data/test/test_ggn_state.rb +0 -29
- data/test/test_ggn_subject.rb +0 -41
- data/test/test_ggn_verb.rb +0 -29
data/lib/sashite/ggn.rb
CHANGED
@@ -1,10 +1,322 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
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")
|
2
10
|
|
3
11
|
module Sashite
|
4
|
-
module
|
5
|
-
|
6
|
-
|
7
|
-
|
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 on basic movement constraints rather
|
16
|
+
# than game-specific legality rules. It answers the fundamental question: "Can this
|
17
|
+
# piece, currently on this square, reach that square?" while remaining neutral about
|
18
|
+
# higher-level game rules like check, ko, repetition, or castling paths.
|
19
|
+
#
|
20
|
+
# = Key Features
|
21
|
+
#
|
22
|
+
# - **Rule-agnostic**: Works with any abstract strategy board game
|
23
|
+
# - **Pseudo-legal** focus: Describes basic movement constraints only
|
24
|
+
# - **JSON-based**: Structured, machine-readable format
|
25
|
+
# - **Validation** support: Built-in schema validation
|
26
|
+
# - **Performance** optimized: Optional validation for large datasets
|
27
|
+
# - **Cross-game** compatible: Supports hybrid games and variants
|
28
|
+
#
|
29
|
+
# = Related Specifications
|
30
|
+
#
|
31
|
+
# GGN works alongside other Sashité specifications:
|
32
|
+
# - **GAN** (General Actor Notation): Unique piece identifiers
|
33
|
+
# - **FEEN** (Forsyth-Edwards Enhanced Notation): Board position representation
|
34
|
+
# - **PMN** (Portable Move Notation): Move sequence representation
|
35
|
+
#
|
36
|
+
# @author Sashité <https://sashite.com/>
|
37
|
+
# @version 1.0.0
|
38
|
+
# @see https://sashite.dev/documents/ggn/1.0.0/ Official GGN Specification
|
39
|
+
# @see https://sashite.dev/schemas/ggn/1.0.0/schema.json JSON Schema
|
40
|
+
module Ggn
|
41
|
+
class << self
|
42
|
+
# Loads and validates a GGN JSON file from the filesystem.
|
43
|
+
#
|
44
|
+
# This method provides a complete pipeline for loading GGN data:
|
45
|
+
# 1. Reads the JSON file from the filesystem with proper encoding
|
46
|
+
# 2. Parses the JSON content into a Ruby Hash with error handling
|
47
|
+
# 3. Optionally validates the structure against the GGN JSON Schema
|
48
|
+
# 4. Creates and returns a Ruleset instance for querying moves
|
49
|
+
#
|
50
|
+
# @param filepath [String, Pathname] Path to the GGN JSON file to load.
|
51
|
+
# Supports both relative and absolute paths.
|
52
|
+
# @param validate [Boolean] Whether to validate against GGN schema (default: true).
|
53
|
+
# Set to false to skip validation for improved performance on large documents.
|
54
|
+
# @param encoding [String] File encoding to use when reading (default: 'UTF-8').
|
55
|
+
# Most GGN files should use UTF-8 encoding.
|
56
|
+
#
|
57
|
+
# @return [Ruleset] A Ruleset instance containing the parsed and validated GGN data.
|
58
|
+
# Use this instance to query pseudo-legal moves for specific pieces and positions.
|
59
|
+
#
|
60
|
+
# @raise [ValidationError] If any of the following conditions occur:
|
61
|
+
# - File doesn't exist or cannot be read
|
62
|
+
# - File contains invalid JSON syntax
|
63
|
+
# - File permissions prevent reading
|
64
|
+
# - When validation is enabled: data doesn't conform to GGN schema
|
65
|
+
#
|
66
|
+
# @example Loading a chess piece definition with full validation
|
67
|
+
# begin
|
68
|
+
# piece_data = Sashite::Ggn.load_file('data/chess_pieces.json')
|
69
|
+
# chess_king_source = piece_data.select('CHESS:K')
|
70
|
+
# puts "Loaded chess king movement rules successfully"
|
71
|
+
# rescue Sashite::Ggn::ValidationError => e
|
72
|
+
# puts "Failed to load chess pieces: #{e.message}"
|
73
|
+
# end
|
74
|
+
#
|
75
|
+
# @example Complete workflow with move evaluation
|
76
|
+
# begin
|
77
|
+
# piece_data = Sashite::Ggn.load_file('data/chess.json')
|
78
|
+
# source = piece_data.select('CHESS:K')
|
79
|
+
# destinations = source.from('e1')
|
80
|
+
# engine = destinations.to('e2')
|
81
|
+
#
|
82
|
+
# board_state = { 'e1' => 'CHESS:K', 'e2' => nil }
|
83
|
+
# result = engine.evaluate(board_state, {}, 'CHESS')
|
84
|
+
# puts "King can move from e1 to e2" if result
|
85
|
+
# rescue Sashite::Ggn::ValidationError => e
|
86
|
+
# puts "Failed to process move: #{e.message}"
|
87
|
+
# end
|
88
|
+
#
|
89
|
+
# @example Loading large datasets without validation for performance
|
90
|
+
# begin
|
91
|
+
# # Skip validation for large files to improve loading performance
|
92
|
+
# large_dataset = Sashite::Ggn.load_file('data/all_variants.json', validate: false)
|
93
|
+
# puts "Loaded GGN data without validation"
|
94
|
+
# rescue Sashite::Ggn::ValidationError => e
|
95
|
+
# puts "Failed to load dataset: #{e.message}"
|
96
|
+
# end
|
97
|
+
#
|
98
|
+
# @example Handling different file encodings
|
99
|
+
# # Load a GGN file with specific encoding
|
100
|
+
# piece_data = Sashite::Ggn.load_file('legacy_data.json', encoding: 'ISO-8859-1')
|
101
|
+
#
|
102
|
+
# @note Performance Considerations
|
103
|
+
# For large GGN files (>1MB), consider setting validate: false to improve
|
104
|
+
# loading performance. However, this comes with the risk of processing
|
105
|
+
# malformed data. In production environments, validate at least once
|
106
|
+
# before deploying with validation disabled.
|
107
|
+
#
|
108
|
+
# @note Thread Safety
|
109
|
+
# This method is thread-safe for concurrent reads of different files.
|
110
|
+
# However, avoid concurrent access to the same file if it might be
|
111
|
+
# modified during reading.
|
112
|
+
def load_file(filepath, validate: true, encoding: 'UTF-8')
|
113
|
+
# Convert to Pathname for consistent file operations and better error handling
|
114
|
+
file_path = normalize_filepath(filepath)
|
115
|
+
|
116
|
+
# Validate file accessibility before attempting to read
|
117
|
+
validate_file_access(file_path)
|
118
|
+
|
119
|
+
# Parse JSON content with comprehensive error handling
|
120
|
+
data = parse_json_file(file_path, encoding)
|
121
|
+
|
122
|
+
# Validate against GGN schema if requested
|
123
|
+
validate_schema(data, file_path) if validate
|
124
|
+
|
125
|
+
# Create and return Ruleset instance
|
126
|
+
Ruleset.new(data)
|
127
|
+
end
|
128
|
+
|
129
|
+
# Loads GGN data directly from a JSON string.
|
130
|
+
#
|
131
|
+
# This method is useful when you have GGN data as a string (e.g., from a
|
132
|
+
# database, API response, or embedded in your application) rather than a file.
|
133
|
+
#
|
134
|
+
# @param json_string [String] JSON string containing GGN data
|
135
|
+
# @param validate [Boolean] Whether to validate against GGN schema (default: true)
|
136
|
+
#
|
137
|
+
# @return [Ruleset] A Ruleset instance containing the parsed GGN data
|
138
|
+
#
|
139
|
+
# @raise [ValidationError] If the JSON is invalid or doesn't conform to GGN schema
|
140
|
+
#
|
141
|
+
# @example Loading GGN data from a string
|
142
|
+
# ggn_json = '{"CHESS:P": {"e2": {"e4": [{"require": {"e3": "empty", "e4": "empty"}, "perform": {"e2": null, "e4": "CHESS:P"}}]}}}'
|
143
|
+
#
|
144
|
+
# begin
|
145
|
+
# piece_data = Sashite::Ggn.load_string(ggn_json)
|
146
|
+
# pawn_source = piece_data.select('CHESS:P')
|
147
|
+
# puts "Loaded pawn with move from e2 to e4"
|
148
|
+
# rescue Sashite::Ggn::ValidationError => e
|
149
|
+
# puts "Invalid GGN data: #{e.message}"
|
150
|
+
# end
|
151
|
+
#
|
152
|
+
# @example Loading from API response without validation
|
153
|
+
# api_response = fetch_ggn_from_api()
|
154
|
+
# piece_data = Sashite::Ggn.load_string(api_response.body, validate: false)
|
155
|
+
def load_string(json_string, validate: true)
|
156
|
+
# Parse JSON string with error handling
|
157
|
+
begin
|
158
|
+
data = ::JSON.parse(json_string)
|
159
|
+
rescue ::JSON::ParserError => e
|
160
|
+
raise ValidationError, "Invalid JSON string: #{e.message}"
|
161
|
+
end
|
162
|
+
|
163
|
+
# Validate against GGN schema if requested
|
164
|
+
validate_schema(data, "<string>") if validate
|
165
|
+
|
166
|
+
# Create and return Ruleset instance
|
167
|
+
Ruleset.new(data)
|
168
|
+
end
|
169
|
+
|
170
|
+
# Loads GGN data from a Ruby Hash.
|
171
|
+
#
|
172
|
+
# This method is useful when you already have parsed JSON data as a Hash
|
173
|
+
# and want to create a GGN Ruleset instance with optional validation.
|
174
|
+
#
|
175
|
+
# @param data [Hash] Ruby Hash containing GGN data structure
|
176
|
+
# @param validate [Boolean] Whether to validate against GGN schema (default: true)
|
177
|
+
#
|
178
|
+
# @return [Ruleset] A Ruleset instance containing the GGN data
|
179
|
+
#
|
180
|
+
# @raise [ValidationError] If the data doesn't conform to GGN schema (when validation enabled)
|
181
|
+
#
|
182
|
+
# @example Creating from existing Hash data
|
183
|
+
# ggn_data = {
|
184
|
+
# "SHOGI:K" => {
|
185
|
+
# "5i" => {
|
186
|
+
# "4i" => [{ "require" => { "4i" => "empty" }, "perform" => { "5i" => nil, "4i" => "SHOGI:K" } }],
|
187
|
+
# "6i" => [{ "require" => { "6i" => "empty" }, "perform" => { "5i" => nil, "6i" => "SHOGI:K" } }]
|
188
|
+
# }
|
189
|
+
# }
|
190
|
+
# }
|
191
|
+
#
|
192
|
+
# piece_data = Sashite::Ggn.load_hash(ggn_data)
|
193
|
+
# shogi_king = piece_data.select('SHOGI:K')
|
194
|
+
def load_hash(data, validate: true)
|
195
|
+
unless data.is_a?(Hash)
|
196
|
+
raise ValidationError, "Expected Hash, got #{data.class}"
|
197
|
+
end
|
198
|
+
|
199
|
+
# Validate against GGN schema if requested
|
200
|
+
validate_schema(data, "<hash>") if validate
|
201
|
+
|
202
|
+
# Create and return Ruleset instance
|
203
|
+
Ruleset.new(data)
|
204
|
+
end
|
205
|
+
|
206
|
+
# Validates a data structure against the GGN JSON Schema.
|
207
|
+
#
|
208
|
+
# This method can be used independently to validate GGN data without
|
209
|
+
# creating a Ruleset instance. Useful for pre-validation or testing.
|
210
|
+
#
|
211
|
+
# @param data [Hash] The data structure to validate
|
212
|
+
# @param context [String] Context information for error messages (default: "<data>")
|
213
|
+
#
|
214
|
+
# @return [true] If validation passes
|
215
|
+
#
|
216
|
+
# @raise [ValidationError] If validation fails with detailed error information
|
217
|
+
#
|
218
|
+
# @example Validating data before processing
|
219
|
+
# begin
|
220
|
+
# Sashite::Ggn.validate!(my_data)
|
221
|
+
# puts "Data is valid GGN format"
|
222
|
+
# rescue Sashite::Ggn::ValidationError => e
|
223
|
+
# puts "Validation failed: #{e.message}"
|
224
|
+
# end
|
225
|
+
def validate!(data, context: "<data>")
|
226
|
+
validate_schema(data, context)
|
227
|
+
true
|
228
|
+
end
|
229
|
+
|
230
|
+
# Checks if a data structure is valid GGN format.
|
231
|
+
#
|
232
|
+
# @param data [Hash] The data structure to validate
|
233
|
+
#
|
234
|
+
# @return [Boolean] true if valid, false otherwise
|
235
|
+
#
|
236
|
+
# @example Checking validity without raising exceptions
|
237
|
+
# if Sashite::Ggn.valid?(my_data)
|
238
|
+
# puts "Data is valid"
|
239
|
+
# else
|
240
|
+
# puts "Data is invalid"
|
241
|
+
# end
|
242
|
+
def valid?(data)
|
243
|
+
schemer = ::JSONSchemer.schema(Schema)
|
244
|
+
schemer.valid?(data)
|
245
|
+
end
|
246
|
+
|
247
|
+
# Returns detailed validation errors for a data structure.
|
248
|
+
#
|
249
|
+
# @param data [Hash] The data structure to validate
|
250
|
+
#
|
251
|
+
# @return [Array<String>] Array of validation error messages (empty if valid)
|
252
|
+
#
|
253
|
+
# @example Getting detailed validation errors
|
254
|
+
# errors = Sashite::Ggn.validation_errors(invalid_data)
|
255
|
+
# if errors.any?
|
256
|
+
# puts "Validation errors found:"
|
257
|
+
# errors.each { |error| puts " - #{error}" }
|
258
|
+
# end
|
259
|
+
def validation_errors(data)
|
260
|
+
schemer = ::JSONSchemer.schema(Schema)
|
261
|
+
schemer.validate(data).map(&:to_s)
|
262
|
+
end
|
263
|
+
|
264
|
+
private
|
265
|
+
|
266
|
+
# Normalizes filepath input to Pathname instance
|
267
|
+
def normalize_filepath(filepath)
|
268
|
+
case filepath
|
269
|
+
when ::Pathname
|
270
|
+
filepath
|
271
|
+
when String
|
272
|
+
::Pathname.new(filepath)
|
273
|
+
else
|
274
|
+
raise ValidationError, "Invalid filepath type: #{filepath.class}. Expected String or Pathname."
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
# Validates that a file exists and is readable
|
279
|
+
def validate_file_access(file_path)
|
280
|
+
unless file_path.exist?
|
281
|
+
raise ValidationError, "File not found: #{file_path}"
|
282
|
+
end
|
283
|
+
|
284
|
+
unless file_path.readable?
|
285
|
+
raise ValidationError, "File not readable: #{file_path}"
|
286
|
+
end
|
287
|
+
|
288
|
+
unless file_path.file?
|
289
|
+
raise ValidationError, "Path is not a file: #{file_path}"
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
# Parses JSON file with proper error handling and encoding
|
294
|
+
def parse_json_file(file_path, encoding)
|
295
|
+
# Read file with specified encoding
|
296
|
+
content = file_path.read(encoding: encoding)
|
297
|
+
|
298
|
+
# Parse JSON content
|
299
|
+
::JSON.parse(content)
|
300
|
+
rescue ::JSON::ParserError => e
|
301
|
+
raise ValidationError, "Invalid JSON in file #{file_path}: #{e.message}"
|
302
|
+
rescue ::Encoding::UndefinedConversionError => e
|
303
|
+
raise ValidationError, "Encoding error in file #{file_path}: #{e.message}. Try a different encoding."
|
304
|
+
rescue ::SystemCallError => e
|
305
|
+
raise ValidationError, "Failed to read file #{file_path}: #{e.message}"
|
306
|
+
end
|
307
|
+
|
308
|
+
# Validates data against GGN schema with detailed error reporting
|
309
|
+
def validate_schema(data, context)
|
310
|
+
schemer = ::JSONSchemer.schema(Schema)
|
311
|
+
|
312
|
+
return if schemer.valid?(data)
|
313
|
+
|
314
|
+
# Collect all validation errors for comprehensive feedback
|
315
|
+
errors = schemer.validate(data).map(&:to_s)
|
316
|
+
error_summary = errors.size == 1 ? "1 validation error" : "#{errors.size} validation errors"
|
317
|
+
|
318
|
+
raise ValidationError, "Invalid GGN data in #{context}: #{error_summary}: #{errors.join('; ')}"
|
319
|
+
end
|
8
320
|
end
|
9
321
|
end
|
10
322
|
end
|
data/lib/sashite-ggn.rb
CHANGED
@@ -1 +1,112 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
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 works alongside other Sashité specifications:
|
10
|
+
# - GAN (General Actor Notation): Unique piece identifiers
|
11
|
+
# - FEEN (Forsyth-Edwards Enhanced Notation): Board position representation
|
12
|
+
# - PMN (Portable Move Notation): Move sequence representation
|
13
|
+
#
|
14
|
+
# @author Sashité <https://sashite.com/>
|
15
|
+
# @version 1.0.0
|
16
|
+
# @see https://sashite.dev/documents/ggn/1.0.0/ GGN Specification
|
17
|
+
# @see https://github.com/sashite/ggn.rb Official Ruby implementation
|
18
|
+
#
|
19
|
+
# @example Basic usage with a chess pawn double move
|
20
|
+
# # Load GGN data from file
|
21
|
+
# require "sashite/ggn"
|
22
|
+
#
|
23
|
+
# piece_data = Sashite::Ggn.load_file("chess_moves.json")
|
24
|
+
# engine = piece_data.select("CHESS:P").from("e2").to("e4")
|
25
|
+
#
|
26
|
+
# # Check if the move is valid given current board state
|
27
|
+
# board_state = {
|
28
|
+
# "e2" => "CHESS:P", # White pawn on e2
|
29
|
+
# "e3" => nil, # Empty square
|
30
|
+
# "e4" => nil # Empty square
|
31
|
+
# }
|
32
|
+
#
|
33
|
+
# result = engine.evaluate(board_state, {}, "CHESS")
|
34
|
+
#
|
35
|
+
# if result
|
36
|
+
# puts "Move is valid!"
|
37
|
+
# puts "Board changes: #{result.diff}"
|
38
|
+
# # => { "e2" => nil, "e4" => "CHESS:P" }
|
39
|
+
# puts "Piece gained: #{result.gain}" # => nil (no capture)
|
40
|
+
# puts "Piece dropped: #{result.drop}" # => nil (not a drop move)
|
41
|
+
# else
|
42
|
+
# puts "Move is not valid under current conditions"
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# @example Piece drops in Shogi
|
46
|
+
# # Shogi allows captured pieces to be dropped back onto the board
|
47
|
+
# piece_data = Sashite::Ggn.load_file("shogi_moves.json")
|
48
|
+
# engine = piece_data.select("SHOGI:P").from("*").to("5e")
|
49
|
+
#
|
50
|
+
# # Player has captured pawns available
|
51
|
+
# captures = { "SHOGI:P" => 2 }
|
52
|
+
#
|
53
|
+
# # Current board state (5th file is clear of unpromoted pawns)
|
54
|
+
# board_state = {
|
55
|
+
# "5e" => nil, # Target square is empty
|
56
|
+
# "5a" => nil, "5b" => nil, "5c" => nil, "5d" => nil,
|
57
|
+
# "5f" => nil, "5g" => nil, "5h" => nil, "5i" => nil
|
58
|
+
# }
|
59
|
+
#
|
60
|
+
# result = engine.evaluate(board_state, captures, "SHOGI")
|
61
|
+
#
|
62
|
+
# if result
|
63
|
+
# puts "Pawn drop is valid!"
|
64
|
+
# puts "Board changes: #{result.diff}" # => { "5e" => "SHOGI:P" }
|
65
|
+
# puts "Piece dropped from hand: #{result.drop}" # => "SHOGI:P"
|
66
|
+
# end
|
67
|
+
#
|
68
|
+
# @example Captures with piece promotion
|
69
|
+
# # A chess pawn capturing and promoting to queen
|
70
|
+
# piece_data = Sashite::Ggn.load_file("chess_moves.json")
|
71
|
+
# engine = piece_data.select("CHESS:P").from("g7").to("h8")
|
72
|
+
#
|
73
|
+
# # Board with enemy piece on h8
|
74
|
+
# board_state = {
|
75
|
+
# "g7" => "CHESS:P", # Our pawn ready to promote
|
76
|
+
# "h8" => "chess:r" # Enemy rook (lowercase = opponent)
|
77
|
+
# }
|
78
|
+
#
|
79
|
+
# result = engine.evaluate(board_state, {}, "CHESS")
|
80
|
+
#
|
81
|
+
# if result
|
82
|
+
# puts "Pawn promotes and captures!"
|
83
|
+
# puts "Final position: #{result.diff}"
|
84
|
+
# # => { "g7" => nil, "h8" => "CHESS:Q" }
|
85
|
+
# puts "Captured piece: #{result.gain}" # => nil (no capture _in hand_)
|
86
|
+
# end
|
87
|
+
#
|
88
|
+
# @example Loading GGN data from different sources
|
89
|
+
# # From file
|
90
|
+
# piece_data = Sashite::Ggn.load_file("moves.json")
|
91
|
+
#
|
92
|
+
# # From JSON string
|
93
|
+
# json_string = '{"CHESS:K": {"e1": {"e2": [{"perform": {"e1": null, "e2": "CHESS:K"}}]}}}'
|
94
|
+
# piece_data = Sashite::Ggn.load_string(json_string)
|
95
|
+
#
|
96
|
+
# # From Hash
|
97
|
+
# ggn_hash = { "CHESS:K" => { "e1" => { "e2" => [{ "perform" => { "e1" => nil, "e2" => "CHESS:K" } }] } } }
|
98
|
+
# piece_data = Sashite::Ggn.load_hash(ggn_hash)
|
99
|
+
module Sashite
|
100
|
+
# Base namespace for all Sashité notation libraries.
|
101
|
+
#
|
102
|
+
# Sashité provides a comprehensive suite of specifications and implementations
|
103
|
+
# for representing abstract strategy board games in a rule-agnostic manner.
|
104
|
+
# This allows for unified game engines, cross-game analysis, and hybrid
|
105
|
+
# game variants.
|
106
|
+
#
|
107
|
+
# @see https://sashite.com/ Official Sashité website
|
108
|
+
# @see https://sashite.dev/ Developer documentation and specifications
|
109
|
+
end
|
110
|
+
|
111
|
+
# Load the main GGN implementation
|
112
|
+
require_relative "sashite/ggn"
|
metadata
CHANGED
@@ -1,98 +1,60 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sashite-ggn
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
- Cyril
|
8
|
-
autorequire:
|
7
|
+
- Cyril Kato
|
9
8
|
bindir: bin
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
13
|
+
name: json_schemer
|
15
14
|
requirement: !ruby/object:Gem::Requirement
|
16
15
|
requirements:
|
17
16
|
- - "~>"
|
18
17
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
20
|
-
type: :
|
18
|
+
version: 2.4.0
|
19
|
+
type: :runtime
|
21
20
|
prerelease: false
|
22
21
|
version_requirements: !ruby/object:Gem::Requirement
|
23
22
|
requirements:
|
24
23
|
- - "~>"
|
25
24
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
version: '5'
|
34
|
-
type: :development
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - "~>"
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '5'
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: rake
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - "~>"
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '10'
|
48
|
-
type: :development
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - "~>"
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '10'
|
55
|
-
description: A Ruby interface for GGN (General Gameplay Notation) objects.
|
56
|
-
email:
|
57
|
-
- contact@cyril.io
|
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 moves in abstract
|
28
|
+
strategy board games. This library provides parsing, validation, and evaluation
|
29
|
+
capabilities for GGN documents, enabling game engines to work with movement rules
|
30
|
+
across different board games including Chess, Shogi, Xiangqi, and custom variants.
|
31
|
+
email: contact@cyril.email
|
58
32
|
executables: []
|
59
33
|
extensions: []
|
60
34
|
extra_rdoc_files: []
|
61
35
|
files:
|
62
|
-
- ".gitignore"
|
63
|
-
- ".ruby-version"
|
64
|
-
- ".travis.yml"
|
65
|
-
- Gemfile
|
66
36
|
- LICENSE.md
|
67
37
|
- README.md
|
68
|
-
- Rakefile
|
69
|
-
- VERSION.semver
|
70
38
|
- lib/sashite-ggn.rb
|
71
39
|
- lib/sashite/ggn.rb
|
72
|
-
- lib/sashite/ggn/
|
73
|
-
- lib/sashite/ggn/
|
74
|
-
- lib/sashite/ggn/
|
75
|
-
- lib/sashite/ggn/
|
76
|
-
- lib/sashite/ggn/
|
77
|
-
- lib/sashite/ggn/
|
78
|
-
- lib/sashite/ggn/
|
79
|
-
- lib/sashite/ggn/
|
80
|
-
- sashite-ggn.gemspec
|
81
|
-
- test/_test_helper.rb
|
82
|
-
- test/test_ggn.rb
|
83
|
-
- test/test_ggn_ability.rb
|
84
|
-
- test/test_ggn_gameplay.rb
|
85
|
-
- test/test_ggn_object.rb
|
86
|
-
- test/test_ggn_pattern.rb
|
87
|
-
- test/test_ggn_square.rb
|
88
|
-
- test/test_ggn_state.rb
|
89
|
-
- test/test_ggn_subject.rb
|
90
|
-
- test/test_ggn_verb.rb
|
40
|
+
- lib/sashite/ggn/move_validator.rb
|
41
|
+
- lib/sashite/ggn/ruleset.rb
|
42
|
+
- lib/sashite/ggn/ruleset/source.rb
|
43
|
+
- lib/sashite/ggn/ruleset/source/destination.rb
|
44
|
+
- lib/sashite/ggn/ruleset/source/destination/engine.rb
|
45
|
+
- lib/sashite/ggn/ruleset/source/destination/engine/transition.rb
|
46
|
+
- lib/sashite/ggn/schema.rb
|
47
|
+
- lib/sashite/ggn/validation_error.rb
|
91
48
|
homepage: https://github.com/sashite/ggn.rb
|
92
49
|
licenses:
|
93
50
|
- MIT
|
94
|
-
metadata:
|
95
|
-
|
51
|
+
metadata:
|
52
|
+
bug_tracker_uri: https://github.com/sashite/ggn.rb/issues
|
53
|
+
documentation_uri: https://rubydoc.info/github/sashite/ggn.rb/main
|
54
|
+
homepage_uri: https://github.com/sashite/ggn.rb
|
55
|
+
source_code_uri: https://github.com/sashite/ggn.rb
|
56
|
+
specification_uri: https://sashite.dev/documents/ggn/1.0.0/
|
57
|
+
rubygems_mfa_required: 'true'
|
96
58
|
rdoc_options: []
|
97
59
|
require_paths:
|
98
60
|
- lib
|
@@ -100,26 +62,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
100
62
|
requirements:
|
101
63
|
- - ">="
|
102
64
|
- !ruby/object:Gem::Version
|
103
|
-
version:
|
65
|
+
version: 3.2.0
|
104
66
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
105
67
|
requirements:
|
106
68
|
- - ">="
|
107
69
|
- !ruby/object:Gem::Version
|
108
70
|
version: '0'
|
109
71
|
requirements: []
|
110
|
-
|
111
|
-
rubygems_version: 2.2.2
|
112
|
-
signing_key:
|
72
|
+
rubygems_version: 3.6.9
|
113
73
|
specification_version: 4
|
114
|
-
summary:
|
115
|
-
test_files:
|
116
|
-
- test/_test_helper.rb
|
117
|
-
- test/test_ggn.rb
|
118
|
-
- test/test_ggn_ability.rb
|
119
|
-
- test/test_ggn_gameplay.rb
|
120
|
-
- test/test_ggn_object.rb
|
121
|
-
- test/test_ggn_pattern.rb
|
122
|
-
- test/test_ggn_square.rb
|
123
|
-
- test/test_ggn_state.rb
|
124
|
-
- test/test_ggn_subject.rb
|
125
|
-
- test/test_ggn_verb.rb
|
74
|
+
summary: General Gameplay Notation (GGN) parser and validator for Ruby
|
75
|
+
test_files: []
|
data/.gitignore
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
*.gem
|
2
|
-
*.rbc
|
3
|
-
.bundle
|
4
|
-
.config
|
5
|
-
.yardoc
|
6
|
-
Gemfile.lock
|
7
|
-
InstalledFiles
|
8
|
-
_yardoc
|
9
|
-
coverage
|
10
|
-
doc/
|
11
|
-
lib/bundler/man
|
12
|
-
pkg
|
13
|
-
rdoc
|
14
|
-
spec/reports
|
15
|
-
test/tmp
|
16
|
-
test/version_tmp
|
17
|
-
tmp
|
18
|
-
*.bundle
|
19
|
-
*.so
|
20
|
-
*.o
|
21
|
-
*.a
|
22
|
-
mkmf.log
|
data/.ruby-version
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
2.1.2
|
data/.travis.yml
DELETED
data/Gemfile
DELETED
data/Rakefile
DELETED
data/VERSION.semver
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
0.2.0
|
data/lib/sashite/ggn/ability.rb
DELETED
data/lib/sashite/ggn/gameplay.rb
DELETED