sashite-snn 1.0.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 +7 -0
- data/LICENSE.md +22 -0
- data/README.md +261 -0
- data/lib/sashite/snn/style.rb +143 -0
- data/lib/sashite/snn.rb +49 -0
- data/lib/sashite-snn.rb +18 -0
- metadata +56 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 189a182b820d000660357679c628df3f1adf451b8fd462f4e667ba9170453a03
|
4
|
+
data.tar.gz: 17a1049e333427994c977efe5c1170fa8114685515f0ff91b9abfb4bcdbe5963
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6843ef5ffa7f5affa4acfe88b52eb1b837112c853d0668df67f75ac3aedbe1e0f569bd52941626417cf0a66956d472bab61f7f76fedf531a36c6fe60695f0539
|
7
|
+
data.tar.gz: 8b641153ba70b214a4bf7176169d9f456a771347851ec50618777f86b2129381c3f3b6bdb4ccb98b42975651e2d6c14930e69a42bfc233b795251ac2d14fea10
|
data/LICENSE.md
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2025 Cyril Kato
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,261 @@
|
|
1
|
+
# Snn.rb
|
2
|
+
|
3
|
+
[](https://github.com/sashite/snn.rb/tags)
|
4
|
+
[](https://rubydoc.info/github/sashite/snn.rb/main)
|
5
|
+

|
6
|
+
[](https://github.com/sashite/snn.rb/raw/main/LICENSE.md)
|
7
|
+
|
8
|
+
> **SNN** (Style Name Notation) support for the Ruby language.
|
9
|
+
|
10
|
+
## What is SNN?
|
11
|
+
|
12
|
+
SNN (Style Name Notation) is a consistent and rule-agnostic format for identifying piece styles in abstract strategy board games. It provides unambiguous identification of piece styles by using standardized naming conventions, enabling clear distinction between different piece traditions, variants, or design approaches within multi-style gaming environments.
|
13
|
+
|
14
|
+
This gem implements the [SNN Specification v1.0.0](https://sashite.dev/documents/snn/1.0.0/), providing a Ruby interface for working with style identifiers through a clean and minimal API.
|
15
|
+
|
16
|
+
## Installation
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
# In your Gemfile
|
20
|
+
gem "sashite-snn"
|
21
|
+
```
|
22
|
+
|
23
|
+
Or install manually:
|
24
|
+
|
25
|
+
```sh
|
26
|
+
gem install sashite-snn
|
27
|
+
```
|
28
|
+
|
29
|
+
## SNN Format
|
30
|
+
|
31
|
+
A SNN record consists of an identifier starting with an alphabetic character, followed by optional alphabetic characters and digits:
|
32
|
+
|
33
|
+
```
|
34
|
+
<style-id>
|
35
|
+
```
|
36
|
+
|
37
|
+
Where:
|
38
|
+
- The identifier starts with an alphabetic character (`A-Z` for uppercase, `a-z` for lowercase)
|
39
|
+
- Subsequent characters may include alphabetic characters and digits (`A-Z`, `0-9` for uppercase styles; `a-z`, `0-9` for lowercase styles)
|
40
|
+
- **Uppercase** format denotes styles belonging to the first player
|
41
|
+
- **Lowercase** format denotes styles belonging to the second player
|
42
|
+
- The entire identifier must be entirely uppercase or entirely lowercase
|
43
|
+
|
44
|
+
## Basic Usage
|
45
|
+
|
46
|
+
### Creating Style Objects
|
47
|
+
|
48
|
+
The primary interface is the `Sashite::Snn::Style` class, which represents a style identifier in SNN format:
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
require "sashite/snn"
|
52
|
+
|
53
|
+
# Parse a SNN string into a style object
|
54
|
+
style = Sashite::Snn::Style.parse("CHESS")
|
55
|
+
# => #<Sashite::Snn::Style:0x... @identifier="CHESS">
|
56
|
+
|
57
|
+
lowercase_style = Sashite::Snn::Style.parse("shogi")
|
58
|
+
# => #<Sashite::Snn::Style:0x... @identifier="shogi">
|
59
|
+
|
60
|
+
# Create directly with constructor
|
61
|
+
style = Sashite::Snn::Style.new("CHESS")
|
62
|
+
lowercase_style = Sashite::Snn::Style.new("makruk")
|
63
|
+
|
64
|
+
# Convenience method
|
65
|
+
style = Sashite::Snn.style("XIANGQI")
|
66
|
+
```
|
67
|
+
|
68
|
+
### Converting to String and Symbol
|
69
|
+
|
70
|
+
Convert a style object to different representations:
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
style = Sashite::Snn::Style.parse("CHESS")
|
74
|
+
style.to_s # => "CHESS"
|
75
|
+
style.to_sym # => :CHESS
|
76
|
+
|
77
|
+
variant_style = Sashite::Snn::Style.parse("chess960")
|
78
|
+
variant_style.to_s # => "chess960"
|
79
|
+
variant_style.to_sym # => :chess960
|
80
|
+
|
81
|
+
# Useful for hash keys and case statements
|
82
|
+
game_config = {
|
83
|
+
style.to_sym => { pieces: chess_pieces, rules: chess_rules }
|
84
|
+
}
|
85
|
+
|
86
|
+
case style.to_sym
|
87
|
+
when :CHESS then setup_chess_game
|
88
|
+
when :SHOGI then setup_shogi_game
|
89
|
+
end
|
90
|
+
```
|
91
|
+
|
92
|
+
### Player Association
|
93
|
+
|
94
|
+
Check which player a style belongs to:
|
95
|
+
|
96
|
+
```ruby
|
97
|
+
first_player_style = Sashite::Snn::Style.parse("CHESS")
|
98
|
+
first_player_style.first_player? # => true
|
99
|
+
first_player_style.second_player? # => false
|
100
|
+
|
101
|
+
second_player_style = Sashite::Snn::Style.parse("shogi")
|
102
|
+
second_player_style.first_player? # => false
|
103
|
+
second_player_style.second_player? # => true
|
104
|
+
```
|
105
|
+
|
106
|
+
## Validation
|
107
|
+
|
108
|
+
All parsing automatically validates input according to the SNN specification:
|
109
|
+
|
110
|
+
```ruby
|
111
|
+
# Valid SNN strings
|
112
|
+
Sashite::Snn::Style.parse("CHESS") # ✓
|
113
|
+
Sashite::Snn::Style.parse("shogi") # ✓
|
114
|
+
Sashite::Snn::Style.parse("CHESS960") # ✓
|
115
|
+
Sashite::Snn::Style.parse("makruk") # ✓
|
116
|
+
|
117
|
+
# Valid constructor calls
|
118
|
+
Sashite::Snn::Style.new("XIANGQI") # ✓
|
119
|
+
Sashite::Snn::Style.new("janggi") # ✓
|
120
|
+
|
121
|
+
# Convenience method
|
122
|
+
Sashite::Snn.style("MINISHOGI") # ✓
|
123
|
+
|
124
|
+
# Check validity
|
125
|
+
Sashite::Snn.valid?("CHESS") # => true
|
126
|
+
Sashite::Snn.valid?("Chess") # => false (mixed case)
|
127
|
+
Sashite::Snn.valid?("123") # => false (must start with letter)
|
128
|
+
Sashite::Snn.valid?("") # => false (empty string)
|
129
|
+
|
130
|
+
# Invalid SNN strings raise ArgumentError
|
131
|
+
Sashite::Snn::Style.parse("") # ✗ ArgumentError
|
132
|
+
Sashite::Snn::Style.parse("Chess") # ✗ ArgumentError (mixed case)
|
133
|
+
Sashite::Snn::Style.parse("9CHESS") # ✗ ArgumentError (starts with digit)
|
134
|
+
Sashite::Snn::Style.parse("CHESS-960") # ✗ ArgumentError (contains hyphen)
|
135
|
+
```
|
136
|
+
|
137
|
+
## Examples of SNN in Practice
|
138
|
+
|
139
|
+
### Classic Game Styles
|
140
|
+
|
141
|
+
```ruby
|
142
|
+
# International Chess
|
143
|
+
first_player = Sashite::Snn::Style.parse("CHESS") # First player uses chess pieces
|
144
|
+
second_player = Sashite::Snn::Style.parse("chess") # Second player uses chess pieces
|
145
|
+
|
146
|
+
# Cross-style game: Chess vs Shogi
|
147
|
+
first_player = Sashite::Snn::Style.parse("CHESS") # First player uses chess pieces
|
148
|
+
second_player = Sashite::Snn::Style.parse("shogi") # Second player uses shogi pieces
|
149
|
+
|
150
|
+
# Variant games
|
151
|
+
first_player = Sashite::Snn::Style.parse("CHESS960") # First player uses Chess960 variant
|
152
|
+
second_player = Sashite::Snn::Style.parse("chess960") # Second player uses Chess960 variant
|
153
|
+
```
|
154
|
+
|
155
|
+
### Variant Styles
|
156
|
+
|
157
|
+
```ruby
|
158
|
+
# Chess variants
|
159
|
+
fischer_random = Sashite::Snn::Style.parse("CHESS960")
|
160
|
+
king_of_hill = Sashite::Snn::Style.parse("CHESSKING")
|
161
|
+
|
162
|
+
# Shogi variants
|
163
|
+
mini_shogi = Sashite::Snn::Style.parse("MINISHOGI")
|
164
|
+
handicap_shogi = Sashite::Snn::Style.parse("SHOGI9")
|
165
|
+
|
166
|
+
# Other traditions
|
167
|
+
thai_makruk = Sashite::Snn::Style.parse("MAKRUK")
|
168
|
+
korean_janggi = Sashite::Snn::Style.parse("JANGGI")
|
169
|
+
```
|
170
|
+
|
171
|
+
### Cross-Style Gaming
|
172
|
+
|
173
|
+
```ruby
|
174
|
+
# Create a cross-style game setup
|
175
|
+
first_player_style = Sashite::Snn::Style.parse("CHESS")
|
176
|
+
second_player_style = Sashite::Snn::Style.parse("makruk")
|
177
|
+
|
178
|
+
puts "Game: #{first_player_style} vs #{second_player_style}"
|
179
|
+
# => "Game: CHESS vs makruk"
|
180
|
+
|
181
|
+
# This represents a unique game where chess pieces face makruk pieces
|
182
|
+
|
183
|
+
# Each player keeps their assigned style throughout the game
|
184
|
+
game_config = {
|
185
|
+
first_player: first_player_style, # Fixed: CHESS
|
186
|
+
second_player: second_player_style # Fixed: makruk
|
187
|
+
}
|
188
|
+
|
189
|
+
# Using symbols for configuration
|
190
|
+
style_configs = {
|
191
|
+
first_player_style.to_sym => { piece_set: :western, board: :"8x8" },
|
192
|
+
second_player_style.to_sym => { piece_set: :thai, board: :"8x8" }
|
193
|
+
}
|
194
|
+
```
|
195
|
+
|
196
|
+
## API Reference
|
197
|
+
|
198
|
+
### Module Methods
|
199
|
+
|
200
|
+
- `Sashite::Snn.valid?(snn_string)` - Check if a string is valid SNN notation
|
201
|
+
- `Sashite::Snn.style(identifier)` - Convenience method to create style objects
|
202
|
+
|
203
|
+
### Sashite::Snn::Style Class Methods
|
204
|
+
|
205
|
+
- `Sashite::Snn::Style.parse(snn_string)` - Parse a SNN string into a style object
|
206
|
+
- `Sashite::Snn::Style.new(identifier)` - Create a new style instance
|
207
|
+
|
208
|
+
### Instance Methods
|
209
|
+
|
210
|
+
#### Player Queries
|
211
|
+
- `#first_player?` - Check if style belongs to first player (uppercase)
|
212
|
+
- `#second_player?` - Check if style belongs to second player (lowercase)
|
213
|
+
- `#uppercase?` - Alias for `#first_player?`
|
214
|
+
- `#lowercase?` - Alias for `#second_player?`
|
215
|
+
|
216
|
+
#### Conversion
|
217
|
+
- `#to_s` - Convert to SNN string representation
|
218
|
+
- `#to_sym` - Convert to symbol representation
|
219
|
+
- `#inspect` - Detailed string representation for debugging
|
220
|
+
|
221
|
+
## Properties of SNN
|
222
|
+
|
223
|
+
* **Rule-agnostic**: SNN does not encode game states, legality, validity, or game-specific conditions
|
224
|
+
* **Unambiguous identification**: Different piece styles can coexist without naming conflicts
|
225
|
+
* **Canonical representation**: Equivalent styles yield identical strings
|
226
|
+
* **Cross-style support**: Enables games where players use different piece traditions
|
227
|
+
* **Case consistency**: Each identifier is entirely uppercase or entirely lowercase
|
228
|
+
* **Fixed assignment**: Style assignment to players remains constant throughout a game
|
229
|
+
|
230
|
+
## Constraints
|
231
|
+
|
232
|
+
* SNN supports exactly **two players**
|
233
|
+
* Players are distinguished by casing: **uppercase** for first player, **lowercase** for second player
|
234
|
+
* Style identifiers must start with an alphabetic character
|
235
|
+
* Subsequent characters may include alphabetic characters and digits
|
236
|
+
* Mixed casing is not permitted within a single identifier
|
237
|
+
* Style assignment to players remains **fixed throughout a game**
|
238
|
+
|
239
|
+
## Use Cases
|
240
|
+
|
241
|
+
SNN is particularly useful in the following scenarios:
|
242
|
+
|
243
|
+
1. **Multi-style environments**: When games involve pieces from multiple traditions or variants
|
244
|
+
2. **Game engine development**: When implementing engines that need to distinguish between different piece style traditions
|
245
|
+
3. **Hybrid games**: When creating or analyzing games that combine elements from different piece traditions
|
246
|
+
4. **Database systems**: When storing game data that must avoid naming conflicts between similar styles
|
247
|
+
5. **Cross-tradition analysis**: When comparing or analyzing strategic elements across different piece traditions
|
248
|
+
6. **Tournament systems**: When organizing events that allow players to choose from different piece style traditions
|
249
|
+
|
250
|
+
## Documentation
|
251
|
+
|
252
|
+
- [Official SNN Specification](https://sashite.dev/documents/snn/1.0.0/)
|
253
|
+
- [API Documentation](https://rubydoc.info/github/sashite/snn.rb/main)
|
254
|
+
|
255
|
+
## License
|
256
|
+
|
257
|
+
The [gem](https://rubygems.org/gems/sashite-snn) is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
258
|
+
|
259
|
+
## About Sashité
|
260
|
+
|
261
|
+
This project is maintained by [Sashité](https://sashite.com/) — promoting chess variants and sharing the beauty of Chinese, Japanese, and Western chess cultures.
|
@@ -0,0 +1,143 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sashite
|
4
|
+
module Snn
|
5
|
+
# Represents a style identifier in SNN format
|
6
|
+
#
|
7
|
+
# A style represents a particular tradition, variant, or design approach for game pieces.
|
8
|
+
# The casing of the identifier determines player association:
|
9
|
+
# - Uppercase identifiers belong to the first player
|
10
|
+
# - Lowercase identifiers belong to the second player
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
# # First player styles (uppercase)
|
14
|
+
# chess_style = Sashite::Snn::Style.new("CHESS")
|
15
|
+
# shogi_style = Sashite::Snn::Style.new("SHOGI")
|
16
|
+
#
|
17
|
+
# # Second player styles (lowercase)
|
18
|
+
# makruk_style = Sashite::Snn::Style.new("makruk")
|
19
|
+
# chess960_style = Sashite::Snn::Style.new("chess960")
|
20
|
+
class Style
|
21
|
+
# @return [String] The style identifier
|
22
|
+
attr_reader :identifier
|
23
|
+
|
24
|
+
# Create a new style instance
|
25
|
+
#
|
26
|
+
# @param identifier [String] The style identifier
|
27
|
+
# @raise [ArgumentError] if the identifier is invalid SNN notation
|
28
|
+
#
|
29
|
+
# @example
|
30
|
+
# style = Sashite::Snn::Style.new("CHESS")
|
31
|
+
# # => #<Sashite::Snn::Style:0x... @identifier="CHESS">
|
32
|
+
def initialize(identifier)
|
33
|
+
raise ArgumentError, "Invalid SNN format: #{identifier.inspect}" unless Snn.valid?(identifier)
|
34
|
+
|
35
|
+
@identifier = identifier.freeze
|
36
|
+
|
37
|
+
freeze
|
38
|
+
end
|
39
|
+
|
40
|
+
# Parse a SNN string into a style object
|
41
|
+
#
|
42
|
+
# @param snn_string [String] The SNN string to parse
|
43
|
+
# @return [Sashite::Snn::Style] A new style object
|
44
|
+
# @raise [ArgumentError] if the string is invalid SNN notation
|
45
|
+
#
|
46
|
+
# @example
|
47
|
+
# style = Sashite::Snn::Style.parse("CHESS")
|
48
|
+
# # => #<Sashite::Snn::Style:0x... @identifier="CHESS">
|
49
|
+
def self.parse(snn_string)
|
50
|
+
new(snn_string)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Check if this style belongs to the first player
|
54
|
+
#
|
55
|
+
# @return [Boolean] true if the style is uppercase (first player), false otherwise
|
56
|
+
#
|
57
|
+
# @example
|
58
|
+
# Sashite::Snn::Style.new("CHESS").first_player? # => true
|
59
|
+
# Sashite::Snn::Style.new("shogi").first_player? # => false
|
60
|
+
def first_player?
|
61
|
+
uppercase?
|
62
|
+
end
|
63
|
+
|
64
|
+
# Check if this style belongs to the second player
|
65
|
+
#
|
66
|
+
# @return [Boolean] true if the style is lowercase (second player), false otherwise
|
67
|
+
#
|
68
|
+
# @example
|
69
|
+
# Sashite::Snn::Style.new("CHESS").second_player? # => false
|
70
|
+
# Sashite::Snn::Style.new("shogi").second_player? # => true
|
71
|
+
def second_player?
|
72
|
+
lowercase?
|
73
|
+
end
|
74
|
+
|
75
|
+
# Check if the style identifier is uppercase
|
76
|
+
#
|
77
|
+
# @return [Boolean] true if the identifier is uppercase, false otherwise
|
78
|
+
#
|
79
|
+
# @example
|
80
|
+
# Sashite::Snn::Style.new("CHESS").uppercase? # => true
|
81
|
+
# Sashite::Snn::Style.new("chess").uppercase? # => false
|
82
|
+
def uppercase?
|
83
|
+
identifier == identifier.upcase
|
84
|
+
end
|
85
|
+
|
86
|
+
# Check if the style identifier is lowercase
|
87
|
+
#
|
88
|
+
# @return [Boolean] true if the identifier is lowercase, false otherwise
|
89
|
+
#
|
90
|
+
# @example
|
91
|
+
# Sashite::Snn::Style.new("CHESS").lowercase? # => false
|
92
|
+
# Sashite::Snn::Style.new("chess").lowercase? # => true
|
93
|
+
def lowercase?
|
94
|
+
identifier == identifier.downcase
|
95
|
+
end
|
96
|
+
|
97
|
+
# Convert the style to its string representation
|
98
|
+
#
|
99
|
+
# @return [String] The style identifier
|
100
|
+
#
|
101
|
+
# @example
|
102
|
+
# Sashite::Snn::Style.new("CHESS").to_s # => "CHESS"
|
103
|
+
def to_s
|
104
|
+
identifier
|
105
|
+
end
|
106
|
+
|
107
|
+
# Convert the style to a symbol
|
108
|
+
#
|
109
|
+
# @return [Symbol] The style identifier as a symbol
|
110
|
+
#
|
111
|
+
# @example
|
112
|
+
# Sashite::Snn::Style.new("CHESS").to_sym # => :CHESS
|
113
|
+
def to_sym
|
114
|
+
identifier.to_sym
|
115
|
+
end
|
116
|
+
|
117
|
+
# String representation for debugging
|
118
|
+
#
|
119
|
+
# @return [String] A detailed string representation
|
120
|
+
def inspect
|
121
|
+
"#<#{self.class}:0x#{object_id.to_s(16)} @identifier=#{identifier.inspect}>"
|
122
|
+
end
|
123
|
+
|
124
|
+
# Equality comparison
|
125
|
+
#
|
126
|
+
# @param other [Object] The object to compare with
|
127
|
+
# @return [Boolean] true if both objects are Style instances with the same identifier
|
128
|
+
def ==(other)
|
129
|
+
other.is_a?(Style) && identifier == other.identifier
|
130
|
+
end
|
131
|
+
|
132
|
+
# Alias for equality comparison
|
133
|
+
alias eql? ==
|
134
|
+
|
135
|
+
# Hash code for use in hashes and sets
|
136
|
+
#
|
137
|
+
# @return [Integer] The hash code
|
138
|
+
def hash
|
139
|
+
[self.class, identifier].hash
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
data/lib/sashite/snn.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "snn/style"
|
4
|
+
|
5
|
+
module Sashite
|
6
|
+
# Style Name Notation (SNN) module
|
7
|
+
#
|
8
|
+
# SNN provides a consistent and rule-agnostic format for identifying piece styles
|
9
|
+
# in abstract strategy board games. It enables clear distinction between different
|
10
|
+
# piece traditions, variants, or design approaches within multi-style gaming environments.
|
11
|
+
#
|
12
|
+
# @see https://sashite.dev/documents/snn/1.0.0/ SNN Specification v1.0.0
|
13
|
+
module Snn
|
14
|
+
# SNN validation regular expression
|
15
|
+
# Matches: uppercase style (A-Z followed by A-Z0-9*) or lowercase style (a-z followed by a-z0-9*)
|
16
|
+
VALIDATION_REGEX = /\A([A-Z][A-Z0-9]*|[a-z][a-z0-9]*)\z/
|
17
|
+
|
18
|
+
# Check if a string is valid SNN notation
|
19
|
+
#
|
20
|
+
# @param snn_string [String] The string to validate
|
21
|
+
# @return [Boolean] true if the string is valid SNN notation, false otherwise
|
22
|
+
#
|
23
|
+
# @example
|
24
|
+
# Sashite::Snn.valid?("CHESS") # => true
|
25
|
+
# Sashite::Snn.valid?("shogi") # => true
|
26
|
+
# Sashite::Snn.valid?("Chess") # => false (mixed case)
|
27
|
+
# Sashite::Snn.valid?("123") # => false (must start with letter)
|
28
|
+
# Sashite::Snn.valid?("") # => false (empty string)
|
29
|
+
def self.valid?(snn_string)
|
30
|
+
return false unless snn_string.is_a?(String)
|
31
|
+
return false if snn_string.empty?
|
32
|
+
|
33
|
+
VALIDATION_REGEX.match?(snn_string)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Convenience method to create a style object
|
37
|
+
#
|
38
|
+
# @param identifier [String] The style identifier
|
39
|
+
# @return [Sashite::Snn::Style] A new style object
|
40
|
+
# @raise [ArgumentError] if the identifier is invalid
|
41
|
+
#
|
42
|
+
# @example
|
43
|
+
# style = Sashite::Snn.style("CHESS")
|
44
|
+
# # => #<Sashite::Snn::Style:0x... @identifier="CHESS">
|
45
|
+
def self.style(identifier)
|
46
|
+
Style.new(identifier)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/sashite-snn.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Sashité namespace for board game notation libraries
|
4
|
+
module Sashite
|
5
|
+
# Style Name Notation (SNN) implementation for Ruby
|
6
|
+
#
|
7
|
+
# SNN is a consistent and rule-agnostic format for identifying piece styles
|
8
|
+
# in abstract strategy board games. It provides unambiguous identification
|
9
|
+
# of piece styles by using standardized naming conventions, enabling clear
|
10
|
+
# distinction between different piece traditions, variants, or design
|
11
|
+
# approaches within multi-style gaming environments.
|
12
|
+
#
|
13
|
+
# @see https://sashite.dev/documents/snn/1.0.0/ SNN Specification v1.0.0
|
14
|
+
# @author Sashité
|
15
|
+
# @since 1.0.0
|
16
|
+
end
|
17
|
+
|
18
|
+
require_relative "sashite/snn"
|
metadata
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sashite-snn
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Cyril Kato
|
8
|
+
bindir: bin
|
9
|
+
cert_chain: []
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
11
|
+
dependencies: []
|
12
|
+
description: |
|
13
|
+
A clean, minimal Ruby implementation of Style Name Notation (SNN) for abstract strategy games.
|
14
|
+
SNN provides a consistent and rule-agnostic format for identifying piece styles, enabling
|
15
|
+
clear distinction between different piece traditions, variants, or design approaches within
|
16
|
+
multi-style gaming environments. Features include player-based casing, style validation,
|
17
|
+
and cross-style compatibility. Perfect for game engines, multi-tradition environments,
|
18
|
+
and hybrid gaming systems.
|
19
|
+
email: contact@cyril.email
|
20
|
+
executables: []
|
21
|
+
extensions: []
|
22
|
+
extra_rdoc_files: []
|
23
|
+
files:
|
24
|
+
- LICENSE.md
|
25
|
+
- README.md
|
26
|
+
- lib/sashite-snn.rb
|
27
|
+
- lib/sashite/snn.rb
|
28
|
+
- lib/sashite/snn/style.rb
|
29
|
+
homepage: https://github.com/sashite/snn.rb
|
30
|
+
licenses:
|
31
|
+
- MIT
|
32
|
+
metadata:
|
33
|
+
bug_tracker_uri: https://github.com/sashite/snn.rb/issues
|
34
|
+
documentation_uri: https://rubydoc.info/github/sashite/snn.rb/main
|
35
|
+
homepage_uri: https://github.com/sashite/snn.rb
|
36
|
+
source_code_uri: https://github.com/sashite/snn.rb
|
37
|
+
specification_uri: https://sashite.dev/documents/snn/1.0.0/
|
38
|
+
rubygems_mfa_required: 'true'
|
39
|
+
rdoc_options: []
|
40
|
+
require_paths:
|
41
|
+
- lib
|
42
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 3.2.0
|
47
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: '0'
|
52
|
+
requirements: []
|
53
|
+
rubygems_version: 3.6.7
|
54
|
+
specification_version: 4
|
55
|
+
summary: Style Name Notation (SNN) support for the Ruby language.
|
56
|
+
test_files: []
|