sashite-ggn 0.3.0 → 0.6.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 +73 -339
- data/lib/sashite/ggn/move_validator.rb +208 -0
- data/lib/sashite/ggn/ruleset/source/destination/engine/transition.rb +81 -0
- data/lib/sashite/ggn/ruleset/source/destination/engine.rb +374 -0
- data/lib/sashite/ggn/ruleset/source/destination.rb +111 -0
- data/lib/sashite/ggn/{piece → ruleset}/source.rb +43 -15
- data/lib/sashite/ggn/ruleset.rb +311 -0
- data/lib/sashite/ggn/schema.rb +96 -77
- data/lib/sashite/ggn/validation_error.rb +26 -1
- data/lib/sashite/ggn.rb +36 -35
- data/lib/sashite-ggn.rb +48 -34
- metadata +13 -11
- data/lib/sashite/ggn/piece/source/destination/engine/transition.rb +0 -90
- data/lib/sashite/ggn/piece/source/destination/engine.rb +0 -407
- data/lib/sashite/ggn/piece/source/destination.rb +0 -65
- data/lib/sashite/ggn/piece.rb +0 -77
data/lib/sashite/ggn/schema.rb
CHANGED
@@ -6,8 +6,11 @@ module Sashite
|
|
6
6
|
#
|
7
7
|
# This schema defines the structure and constraints for GGN documents,
|
8
8
|
# which describe pseudo-legal moves in abstract strategy board games.
|
9
|
-
# GGN is rule-agnostic and focuses on
|
10
|
-
#
|
9
|
+
# GGN is rule-agnostic and focuses exclusively on board-to-board transformations:
|
10
|
+
# pieces moving, capturing, or transforming on the game board.
|
11
|
+
#
|
12
|
+
# The schema has been updated to reflect GGN's focus on board transformations only.
|
13
|
+
# Hand management, piece drops, and captures-to-hand are outside the scope of GGN.
|
11
14
|
#
|
12
15
|
# @example Basic GGN document structure
|
13
16
|
# {
|
@@ -23,15 +26,28 @@ module Sashite
|
|
23
26
|
# }
|
24
27
|
# }
|
25
28
|
#
|
26
|
-
# @example Complex move with
|
29
|
+
# @example Complex move with multiple conditions
|
27
30
|
# {
|
28
|
-
# "
|
29
|
-
# "
|
30
|
-
# "
|
31
|
+
# "CHESS:P": {
|
32
|
+
# "d5": {
|
33
|
+
# "e6": [
|
31
34
|
# {
|
32
|
-
# "require": { "e5": "
|
33
|
-
# "perform": { "
|
34
|
-
#
|
35
|
+
# "require": { "e5": "chess:p", "e6": "empty" },
|
36
|
+
# "perform": { "d5": null, "e5": null, "e6": "CHESS:P" }
|
37
|
+
# }
|
38
|
+
# ]
|
39
|
+
# }
|
40
|
+
# }
|
41
|
+
# }
|
42
|
+
#
|
43
|
+
# @example Multi-square move (castling)
|
44
|
+
# {
|
45
|
+
# "CHESS:K": {
|
46
|
+
# "e1": {
|
47
|
+
# "g1": [
|
48
|
+
# {
|
49
|
+
# "require": { "f1": "empty", "g1": "empty", "h1": "CHESS:R" },
|
50
|
+
# "perform": { "e1": null, "f1": "CHESS:R", "g1": "CHESS:K", "h1": null }
|
35
51
|
# }
|
36
52
|
# ]
|
37
53
|
# }
|
@@ -45,7 +61,7 @@ module Sashite
|
|
45
61
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
46
62
|
"$id": "https://sashite.dev/schemas/ggn/1.0.0/schema.json",
|
47
63
|
"title": "General Gameplay Notation (GGN)",
|
48
|
-
"description": "JSON Schema for pseudo-legal moves in abstract board games using the GGN format.",
|
64
|
+
"description": "JSON Schema for pseudo-legal moves in abstract board games using the GGN format. GGN focuses exclusively on board-to-board transformations.",
|
49
65
|
"type": "object",
|
50
66
|
|
51
67
|
# Optional schema reference property
|
@@ -66,82 +82,85 @@ module Sashite
|
|
66
82
|
"type": "object",
|
67
83
|
"minProperties": 1,
|
68
84
|
|
69
|
-
# Source squares: where the piece starts (
|
70
|
-
"
|
71
|
-
"
|
72
|
-
|
85
|
+
# Source squares: where the piece starts (regular board squares only)
|
86
|
+
"patternProperties": {
|
87
|
+
".+": {
|
88
|
+
"type": "object",
|
89
|
+
"minProperties": 1,
|
73
90
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
# Array of conditional transitions for this source->destination pair
|
80
|
-
"items": {
|
81
|
-
"type": "object",
|
82
|
-
"properties": {
|
83
|
-
# Conditions that MUST be satisfied before the move (logical AND)
|
84
|
-
"require": {
|
85
|
-
"type": "object",
|
86
|
-
"minProperties": 1,
|
87
|
-
"additionalProperties": {
|
88
|
-
"type": "string",
|
89
|
-
# Occupation states: "empty", "enemy", or exact GAN identifier
|
90
|
-
"pattern": "^empty$|^enemy$|([A-Z]+:[-+]?[A-Z][']?|[a-z]+:[-+]?[a-z][']?)$"
|
91
|
-
}
|
92
|
-
},
|
91
|
+
# Destination squares: where the piece can move to (regular board squares only)
|
92
|
+
"patternProperties": {
|
93
|
+
".+": {
|
94
|
+
"type": "array",
|
95
|
+
"minItems": 1,
|
93
96
|
|
94
|
-
#
|
95
|
-
"
|
97
|
+
# Array of conditional transitions for this source->destination pair
|
98
|
+
"items": {
|
96
99
|
"type": "object",
|
97
|
-
"
|
98
|
-
|
99
|
-
"
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
100
|
+
"properties": {
|
101
|
+
# Conditions that MUST be satisfied before the move (logical AND)
|
102
|
+
"require": {
|
103
|
+
"type": "object",
|
104
|
+
"minProperties": 1,
|
105
|
+
"patternProperties": {
|
106
|
+
".+": {
|
107
|
+
"type": "string",
|
108
|
+
# Occupation states: "empty", "enemy", or exact GAN identifier
|
109
|
+
"pattern": "^(empty|enemy|[A-Z]+:[-+]?[A-Z][']?|[a-z]+:[-+]?[a-z][']?)$"
|
110
|
+
}
|
111
|
+
},
|
112
|
+
"additionalProperties": false
|
113
|
+
},
|
104
114
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
+
# Conditions that MUST NOT be satisfied before the move (logical OR)
|
116
|
+
"prevent": {
|
117
|
+
"type": "object",
|
118
|
+
"minProperties": 1,
|
119
|
+
"patternProperties": {
|
120
|
+
".+": {
|
121
|
+
"type": "string",
|
122
|
+
# Same occupation states as require
|
123
|
+
"pattern": "^(empty|enemy|[A-Z]+:[-+]?[A-Z][']?|[a-z]+:[-+]?[a-z][']?)$"
|
124
|
+
}
|
115
125
|
},
|
116
|
-
|
117
|
-
|
118
|
-
"type": "null"
|
119
|
-
}
|
120
|
-
]
|
121
|
-
}
|
122
|
-
},
|
126
|
+
"additionalProperties": false
|
127
|
+
},
|
123
128
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
129
|
+
# Board state changes after the move (REQUIRED field)
|
130
|
+
# This is the core of GGN: describing board transformations
|
131
|
+
"perform": {
|
132
|
+
"type": "object",
|
133
|
+
"minProperties": 1,
|
134
|
+
"patternProperties": {
|
135
|
+
".+": {
|
136
|
+
"anyOf": [
|
137
|
+
{
|
138
|
+
# Square contains a piece (GAN identifier)
|
139
|
+
"type": "string",
|
140
|
+
"pattern": "^([A-Z]+:[-+]?[A-Z][']?|[a-z]+:[-+]?[a-z][']?)$"
|
141
|
+
},
|
142
|
+
{
|
143
|
+
# Square becomes empty (null)
|
144
|
+
"type": "null"
|
145
|
+
}
|
146
|
+
]
|
147
|
+
}
|
148
|
+
},
|
149
|
+
"additionalProperties": false
|
150
|
+
}
|
151
|
+
},
|
130
152
|
|
131
|
-
|
132
|
-
|
133
|
-
"
|
134
|
-
|
135
|
-
"pattern": "^([A-Z]+:[A-Z]|[a-z]+:[a-z])$"
|
153
|
+
# Only "perform" is mandatory; "require" and "prevent" are optional
|
154
|
+
# NOTE: "gain" and "drop" fields are no longer supported in GGN
|
155
|
+
"required": ["perform"],
|
156
|
+
"additionalProperties": false
|
136
157
|
}
|
137
|
-
}
|
138
|
-
|
139
|
-
|
140
|
-
"required": ["perform"],
|
141
|
-
"additionalProperties": false
|
142
|
-
}
|
158
|
+
}
|
159
|
+
},
|
160
|
+
"additionalProperties": false
|
143
161
|
}
|
144
|
-
}
|
162
|
+
},
|
163
|
+
"additionalProperties": false
|
145
164
|
}
|
146
165
|
},
|
147
166
|
|
@@ -8,22 +8,47 @@ module Sashite
|
|
8
8
|
# the JSON Schema, contain malformed data, or encounter processing errors
|
9
9
|
# during parsing and evaluation of pseudo-legal moves.
|
10
10
|
#
|
11
|
+
# Since GGN focuses exclusively on board-to-board transformations, validation
|
12
|
+
# errors typically relate to:
|
13
|
+
# - Invalid board position representations
|
14
|
+
# - Malformed GAN identifiers or square labels
|
15
|
+
# - Logical contradictions in require/prevent conditions
|
16
|
+
# - Missing or invalid perform actions
|
17
|
+
#
|
11
18
|
# Common scenarios that raise ValidationError:
|
12
19
|
# - Invalid JSON syntax in GGN files
|
13
20
|
# - Schema validation failures (missing required fields, invalid patterns)
|
14
21
|
# - File system errors (file not found, permission denied)
|
15
22
|
# - Malformed GAN identifiers or square labels
|
16
23
|
# - Logical contradictions in require/prevent conditions
|
24
|
+
# - Invalid board transformation specifications
|
17
25
|
#
|
18
26
|
# @example Handling validation errors during file loading
|
19
27
|
# begin
|
20
|
-
#
|
28
|
+
# piece_data = Sashite::Ggn.load_file('invalid_moves.json')
|
21
29
|
# rescue Sashite::Ggn::ValidationError => e
|
22
30
|
# puts "GGN validation failed: #{e.message}"
|
23
31
|
# # Handle the error appropriately
|
24
32
|
# end
|
25
33
|
#
|
34
|
+
# @example Handling validation errors during move evaluation
|
35
|
+
# begin
|
36
|
+
# transitions = engine.where(board_state, 'CHESS')
|
37
|
+
# rescue Sashite::Ggn::ValidationError => e
|
38
|
+
# puts "Move evaluation failed: #{e.message}"
|
39
|
+
# # Handle invalid board state or parameters
|
40
|
+
# end
|
41
|
+
#
|
42
|
+
# @example Handling schema validation errors
|
43
|
+
# begin
|
44
|
+
# Sashite::Ggn.validate!(ggn_data)
|
45
|
+
# rescue Sashite::Ggn::ValidationError => e
|
46
|
+
# puts "Schema validation failed: #{e.message}"
|
47
|
+
# # The data doesn't conform to GGN specification
|
48
|
+
# end
|
49
|
+
#
|
26
50
|
# @see Sashite::Ggn.load_file Main method that can raise this exception
|
51
|
+
# @see Sashite::Ggn.validate! Schema validation method
|
27
52
|
# @see Sashite::Ggn::Schema JSON Schema used for validation
|
28
53
|
class ValidationError < ::StandardError
|
29
54
|
end
|
data/lib/sashite/ggn.rb
CHANGED
@@ -4,7 +4,7 @@ require 'json'
|
|
4
4
|
require 'json_schemer'
|
5
5
|
require 'pathname'
|
6
6
|
|
7
|
-
require_relative File.join("ggn", "
|
7
|
+
require_relative File.join("ggn", "ruleset")
|
8
8
|
require_relative File.join("ggn", "schema")
|
9
9
|
require_relative File.join("ggn", "validation_error")
|
10
10
|
|
@@ -12,21 +12,22 @@ module Sashite
|
|
12
12
|
# General Gameplay Notation (GGN) module for parsing, validating, and working with
|
13
13
|
# JSON documents that describe pseudo-legal moves in abstract strategy board games.
|
14
14
|
#
|
15
|
-
# GGN is a rule-agnostic format that focuses on
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
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
19
|
#
|
20
|
-
#
|
20
|
+
# = Key Features
|
21
21
|
#
|
22
22
|
# - **Rule-agnostic**: Works with any abstract strategy board game
|
23
|
-
# - **
|
23
|
+
# - **Board-focused**: Describes only board transformations, no hand management
|
24
|
+
# - **Pseudo-legal** focus: Describes basic movement constraints only
|
24
25
|
# - **JSON-based**: Structured, machine-readable format
|
25
|
-
# - **Validation support
|
26
|
-
# - **Performance optimized
|
27
|
-
# - **Cross-game compatible
|
26
|
+
# - **Validation** support: Built-in schema validation
|
27
|
+
# - **Performance** optimized: Optional validation for large datasets
|
28
|
+
# - **Cross-game** compatible: Supports hybrid games and variants
|
28
29
|
#
|
29
|
-
#
|
30
|
+
# = Related Specifications
|
30
31
|
#
|
31
32
|
# GGN works alongside other Sashité specifications:
|
32
33
|
# - **GAN** (General Actor Notation): Unique piece identifiers
|
@@ -45,7 +46,7 @@ module Sashite
|
|
45
46
|
# 1. Reads the JSON file from the filesystem with proper encoding
|
46
47
|
# 2. Parses the JSON content into a Ruby Hash with error handling
|
47
48
|
# 3. Optionally validates the structure against the GGN JSON Schema
|
48
|
-
# 4. Creates and returns a
|
49
|
+
# 4. Creates and returns a Ruleset instance for querying moves
|
49
50
|
#
|
50
51
|
# @param filepath [String, Pathname] Path to the GGN JSON file to load.
|
51
52
|
# Supports both relative and absolute paths.
|
@@ -54,7 +55,7 @@ module Sashite
|
|
54
55
|
# @param encoding [String] File encoding to use when reading (default: 'UTF-8').
|
55
56
|
# Most GGN files should use UTF-8 encoding.
|
56
57
|
#
|
57
|
-
# @return [
|
58
|
+
# @return [Ruleset] A Ruleset instance containing the parsed and validated GGN data.
|
58
59
|
# Use this instance to query pseudo-legal moves for specific pieces and positions.
|
59
60
|
#
|
60
61
|
# @raise [ValidationError] If any of the following conditions occur:
|
@@ -66,7 +67,7 @@ module Sashite
|
|
66
67
|
# @example Loading a chess piece definition with full validation
|
67
68
|
# begin
|
68
69
|
# piece_data = Sashite::Ggn.load_file('data/chess_pieces.json')
|
69
|
-
# chess_king_source = piece_data.
|
70
|
+
# chess_king_source = piece_data.select('CHESS:K')
|
70
71
|
# puts "Loaded chess king movement rules successfully"
|
71
72
|
# rescue Sashite::Ggn::ValidationError => e
|
72
73
|
# puts "Failed to load chess pieces: #{e.message}"
|
@@ -75,13 +76,13 @@ module Sashite
|
|
75
76
|
# @example Complete workflow with move evaluation
|
76
77
|
# begin
|
77
78
|
# piece_data = Sashite::Ggn.load_file('data/chess.json')
|
78
|
-
# source = piece_data.
|
79
|
-
# destinations = source.
|
80
|
-
# engine = destinations.
|
79
|
+
# source = piece_data.select('CHESS:K')
|
80
|
+
# destinations = source.from('e1')
|
81
|
+
# engine = destinations.to('e2')
|
81
82
|
#
|
82
83
|
# board_state = { 'e1' => 'CHESS:K', 'e2' => nil }
|
83
|
-
#
|
84
|
-
# puts "King can move from e1 to e2" if
|
84
|
+
# transitions = engine.where(board_state, 'CHESS')
|
85
|
+
# puts "King can move from e1 to e2" if transitions.any?
|
85
86
|
# rescue Sashite::Ggn::ValidationError => e
|
86
87
|
# puts "Failed to process move: #{e.message}"
|
87
88
|
# end
|
@@ -122,8 +123,8 @@ module Sashite
|
|
122
123
|
# Validate against GGN schema if requested
|
123
124
|
validate_schema(data, file_path) if validate
|
124
125
|
|
125
|
-
# Create and return
|
126
|
-
|
126
|
+
# Create and return Ruleset instance
|
127
|
+
Ruleset.new(data)
|
127
128
|
end
|
128
129
|
|
129
130
|
# Loads GGN data directly from a JSON string.
|
@@ -134,7 +135,7 @@ module Sashite
|
|
134
135
|
# @param json_string [String] JSON string containing GGN data
|
135
136
|
# @param validate [Boolean] Whether to validate against GGN schema (default: true)
|
136
137
|
#
|
137
|
-
# @return [
|
138
|
+
# @return [Ruleset] A Ruleset instance containing the parsed GGN data
|
138
139
|
#
|
139
140
|
# @raise [ValidationError] If the JSON is invalid or doesn't conform to GGN schema
|
140
141
|
#
|
@@ -143,7 +144,7 @@ module Sashite
|
|
143
144
|
#
|
144
145
|
# begin
|
145
146
|
# piece_data = Sashite::Ggn.load_string(ggn_json)
|
146
|
-
# pawn_source = piece_data.
|
147
|
+
# pawn_source = piece_data.select('CHESS:P')
|
147
148
|
# puts "Loaded pawn with move from e2 to e4"
|
148
149
|
# rescue Sashite::Ggn::ValidationError => e
|
149
150
|
# puts "Invalid GGN data: #{e.message}"
|
@@ -163,34 +164,34 @@ module Sashite
|
|
163
164
|
# Validate against GGN schema if requested
|
164
165
|
validate_schema(data, "<string>") if validate
|
165
166
|
|
166
|
-
# Create and return
|
167
|
-
|
167
|
+
# Create and return Ruleset instance
|
168
|
+
Ruleset.new(data)
|
168
169
|
end
|
169
170
|
|
170
171
|
# Loads GGN data from a Ruby Hash.
|
171
172
|
#
|
172
173
|
# This method is useful when you already have parsed JSON data as a Hash
|
173
|
-
# and want to create a GGN
|
174
|
+
# and want to create a GGN Ruleset instance with optional validation.
|
174
175
|
#
|
175
176
|
# @param data [Hash] Ruby Hash containing GGN data structure
|
176
177
|
# @param validate [Boolean] Whether to validate against GGN schema (default: true)
|
177
178
|
#
|
178
|
-
# @return [
|
179
|
+
# @return [Ruleset] A Ruleset instance containing the GGN data
|
179
180
|
#
|
180
181
|
# @raise [ValidationError] If the data doesn't conform to GGN schema (when validation enabled)
|
181
182
|
#
|
182
183
|
# @example Creating from existing Hash data
|
183
184
|
# ggn_data = {
|
184
|
-
# "
|
185
|
-
# "
|
186
|
-
# "
|
187
|
-
# "
|
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" } }]
|
188
189
|
# }
|
189
190
|
# }
|
190
191
|
# }
|
191
192
|
#
|
192
193
|
# piece_data = Sashite::Ggn.load_hash(ggn_data)
|
193
|
-
#
|
194
|
+
# chess_king = piece_data.select('CHESS:K')
|
194
195
|
def load_hash(data, validate: true)
|
195
196
|
unless data.is_a?(Hash)
|
196
197
|
raise ValidationError, "Expected Hash, got #{data.class}"
|
@@ -199,14 +200,14 @@ module Sashite
|
|
199
200
|
# Validate against GGN schema if requested
|
200
201
|
validate_schema(data, "<hash>") if validate
|
201
202
|
|
202
|
-
# Create and return
|
203
|
-
|
203
|
+
# Create and return Ruleset instance
|
204
|
+
Ruleset.new(data)
|
204
205
|
end
|
205
206
|
|
206
207
|
# Validates a data structure against the GGN JSON Schema.
|
207
208
|
#
|
208
209
|
# This method can be used independently to validate GGN data without
|
209
|
-
# creating a
|
210
|
+
# creating a Ruleset instance. Useful for pre-validation or testing.
|
210
211
|
#
|
211
212
|
# @param data [Hash] The data structure to validate
|
212
213
|
# @param context [String] Context information for error messages (default: "<data>")
|
data/lib/sashite-ggn.rb
CHANGED
@@ -6,6 +6,10 @@
|
|
6
6
|
# specification, which is a rule-agnostic, JSON-based format for describing pseudo-legal
|
7
7
|
# moves in abstract strategy board games.
|
8
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
|
+
#
|
9
13
|
# GGN works alongside other Sashité specifications:
|
10
14
|
# - GAN (General Actor Notation): Unique piece identifiers
|
11
15
|
# - FEEN (Forsyth-Edwards Enhanced Notation): Board position representation
|
@@ -21,7 +25,7 @@
|
|
21
25
|
# require "sashite/ggn"
|
22
26
|
#
|
23
27
|
# piece_data = Sashite::Ggn.load_file("chess_moves.json")
|
24
|
-
# engine = piece_data.
|
28
|
+
# engine = piece_data.select("CHESS:P").from("e2").to("e4")
|
25
29
|
#
|
26
30
|
# # Check if the move is valid given current board state
|
27
31
|
# board_state = {
|
@@ -30,59 +34,56 @@
|
|
30
34
|
# "e4" => nil # Empty square
|
31
35
|
# }
|
32
36
|
#
|
33
|
-
#
|
37
|
+
# transitions = engine.where(board_state, "CHESS")
|
34
38
|
#
|
35
|
-
# if
|
39
|
+
# if transitions.any?
|
40
|
+
# transition = transitions.first
|
36
41
|
# puts "Move is valid!"
|
37
|
-
# puts "Board changes: #{
|
42
|
+
# puts "Board changes: #{transition.diff}"
|
38
43
|
# # => { "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
44
|
# else
|
42
45
|
# puts "Move is not valid under current conditions"
|
43
46
|
# end
|
44
47
|
#
|
45
|
-
# @example Piece
|
46
|
-
# #
|
47
|
-
# piece_data = Sashite::Ggn.load_file("
|
48
|
-
# engine = piece_data.
|
49
|
-
#
|
50
|
-
# # Player has captured pawns available
|
51
|
-
# captures = { "SHOGI:P" => 2 }
|
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
52
|
#
|
53
|
-
# #
|
53
|
+
# # Board with pawn ready to promote
|
54
54
|
# board_state = {
|
55
|
-
# "
|
56
|
-
# "
|
57
|
-
# "5f" => nil, "5g" => nil, "5h" => nil, "5i" => nil
|
55
|
+
# "e7" => "CHESS:P", # White pawn on 7th rank
|
56
|
+
# "e8" => nil # Empty promotion square
|
58
57
|
# }
|
59
58
|
#
|
60
|
-
#
|
59
|
+
# transitions = engine.where(board_state, "CHESS")
|
61
60
|
#
|
62
|
-
#
|
63
|
-
#
|
64
|
-
# puts "
|
65
|
-
# puts "Piece dropped from hand: #{result.drop}" # => "SHOGI:P"
|
61
|
+
# transitions.each_with_index do |transition, i|
|
62
|
+
# promoted_piece = transition.diff["e8"]
|
63
|
+
# puts "Promotion choice #{i + 1}: #{promoted_piece}"
|
66
64
|
# end
|
65
|
+
# # Output: CHESS:Q, CHESS:R, CHESS:B, CHESS:N
|
67
66
|
#
|
68
|
-
# @example
|
69
|
-
# #
|
67
|
+
# @example Complex multi-square moves like castling
|
68
|
+
# # Castling involves both king and rook movement
|
70
69
|
# piece_data = Sashite::Ggn.load_file("chess_moves.json")
|
71
|
-
# engine = piece_data.
|
70
|
+
# engine = piece_data.select("CHESS:K").from("e1").to("g1")
|
72
71
|
#
|
73
|
-
# # Board
|
72
|
+
# # Board state allowing kingside castling
|
74
73
|
# board_state = {
|
75
|
-
# "
|
76
|
-
# "
|
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
|
77
78
|
# }
|
78
79
|
#
|
79
|
-
#
|
80
|
+
# transitions = engine.where(board_state, "CHESS")
|
80
81
|
#
|
81
|
-
# if
|
82
|
-
#
|
83
|
-
# puts "
|
84
|
-
#
|
85
|
-
#
|
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 }
|
86
87
|
# end
|
87
88
|
#
|
88
89
|
# @example Loading GGN data from different sources
|
@@ -96,6 +97,19 @@
|
|
96
97
|
# # From Hash
|
97
98
|
# ggn_hash = { "CHESS:K" => { "e1" => { "e2" => [{ "perform" => { "e1" => nil, "e2" => "CHESS:K" } }] } } }
|
98
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
|
+
# }
|
107
|
+
#
|
108
|
+
# all_moves = piece_data.pseudo_legal_transitions(board_state, "CHESS")
|
109
|
+
#
|
110
|
+
# all_moves.each do |actor, origin, target, transitions|
|
111
|
+
# puts "#{actor}: #{origin} → #{target} (#{transitions.size} variants)"
|
112
|
+
# end
|
99
113
|
module Sashite
|
100
114
|
# Base namespace for all Sashité notation libraries.
|
101
115
|
#
|
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.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cyril Kato
|
@@ -24,10 +24,11 @@ dependencies:
|
|
24
24
|
- !ruby/object:Gem::Version
|
25
25
|
version: 2.4.0
|
26
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
|
28
|
-
strategy board games. This library provides parsing,
|
29
|
-
capabilities for GGN documents,
|
30
|
-
|
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.
|
31
32
|
email: contact@cyril.email
|
32
33
|
executables: []
|
33
34
|
extensions: []
|
@@ -37,11 +38,12 @@ files:
|
|
37
38
|
- README.md
|
38
39
|
- lib/sashite-ggn.rb
|
39
40
|
- lib/sashite/ggn.rb
|
40
|
-
- lib/sashite/ggn/
|
41
|
-
- lib/sashite/ggn/
|
42
|
-
- lib/sashite/ggn/
|
43
|
-
- lib/sashite/ggn/
|
44
|
-
- lib/sashite/ggn/
|
41
|
+
- lib/sashite/ggn/move_validator.rb
|
42
|
+
- lib/sashite/ggn/ruleset.rb
|
43
|
+
- lib/sashite/ggn/ruleset/source.rb
|
44
|
+
- lib/sashite/ggn/ruleset/source/destination.rb
|
45
|
+
- lib/sashite/ggn/ruleset/source/destination/engine.rb
|
46
|
+
- lib/sashite/ggn/ruleset/source/destination/engine/transition.rb
|
45
47
|
- lib/sashite/ggn/schema.rb
|
46
48
|
- lib/sashite/ggn/validation_error.rb
|
47
49
|
homepage: https://github.com/sashite/ggn.rb
|
@@ -70,5 +72,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
70
72
|
requirements: []
|
71
73
|
rubygems_version: 3.6.9
|
72
74
|
specification_version: 4
|
73
|
-
summary: General Gameplay Notation (GGN)
|
75
|
+
summary: General Gameplay Notation (GGN) library for board-to-board game transformations
|
74
76
|
test_files: []
|