Snn.rb
SNN (Style Name Notation) implementation for the Ruby language.
What is SNN?
SNN (Style Name Notation) is a foundational, human-readable naming system for identifying game styles in abstract strategy board games. SNN serves as a primitive building block using descriptive alphabetic names with case encoding to represent style identity and player assignment.
Each SNN name is a case-consistent alphabetic identifier where:
-
Uppercase names (e.g.,
CHESS,SHOGI) represent the first player's style -
Lowercase names (e.g.,
chess,shogi) represent the second player's style
This gem implements the SNN Specification v1.0.0 as a foundational primitive with no dependencies.
Installation
# In your Gemfile
gem "sashite-snn"Or install manually:
gem install sashite-snnQuick Start
require "sashite/snn"
# Parse SNN strings into style name objects
name = Sashite::Snn.parse("SHOGI") # => #<Snn::Name value="SHOGI">
name.to_s # => "SHOGI"
name.value # => "SHOGI"
# Create from string or symbol
name = Sashite::Snn.name("CHESS") # => #<Snn::Name value="CHESS">
name = Sashite::Snn::Name.new(:xiangqi) # => #<Snn::Name value="xiangqi">
# Validate SNN strings
Sashite::Snn.valid?("MAKRUK") # => true
Sashite::Snn.valid?("shogi") # => true
Sashite::Snn.valid?("Chess") # => false (mixed case)
Sashite::Snn.valid?("Chess960") # => false (contains digits)SNN Format
An SNN string consists of alphabetic characters only, all in the same case:
<alphabetic-name>
Examples:
-
CHESS— Chess style for first player -
chess— Chess style for second player -
SHOGI— Shōgi style for first player -
shogi— Shōgi style for second player
Format Specification
Structure
<alphabetic-name>
Where the name directly represents the style identity and player assignment through case.
Grammar (BNF)
<snn> ::= <uppercase-name> | <lowercase-name>
<uppercase-name> ::= <uppercase-letter>+
<lowercase-name> ::= <lowercase-letter>+
<uppercase-letter> ::= "A" | "B" | "C" | ... | "Z"
<lowercase-letter> ::= "a" | "b" | "c" | ... | "z"
Regular Expression
/\A([A-Z]+|[a-z]+)\z/Constraints
- Case consistency: All letters must be either uppercase OR lowercase
- Alphabetic only: Only ASCII letters allowed (no digits, no special characters)
- Direct assignment: Names represent styles through explicit association
API Reference
Module Methods
Sashite::Snn.valid?(string)
Returns true if the string is valid SNN notation.
-
Parameter:
string(String) - String to validate -
Returns:
Boolean-trueif valid,falseotherwise
Sashite::Snn.valid?("CHESS") # => true
Sashite::Snn.valid?("shogi") # => true
Sashite::Snn.valid?("Chess") # => false (mixed case)
Sashite::Snn.valid?("CHESS960") # => false (contains digits)
Sashite::Snn.valid?("3DChess") # => false (starts with digit)Sashite::Snn.parse(string)
Parses an SNN string into a Name object.
-
Parameter:
string(String) - SNN notation string -
Returns:
Name- Immutable name object -
Raises:
ArgumentErrorif the string is invalid
name = Sashite::Snn.parse("SHOGI") # => #<Snn::Name value="SHOGI">
name = Sashite::Snn.parse("chess") # => #<Snn::Name value="chess">Sashite::Snn.name(value)
Creates a new Name instance directly.
-
Parameter:
value(String, Symbol) - Style name to construct -
Returns:
Name- New name instance -
Raises:
ArgumentErrorif name format is invalid
Sashite::Snn.name("XIANGQI") # => #<Snn::Name value="XIANGQI">
Sashite::Snn.name(:makruk) # => #<Snn::Name value="makruk">Name Object
The Name object is immutable and provides read-only access to the style name:
name = Sashite::Snn.parse("SHOGI")
name.value # => "SHOGI"
name.to_s # => "SHOGI"
name.frozen? # => trueEquality and hashing:
name1 = Sashite::Snn.parse("CHESS")
name2 = Sashite::Snn.parse("CHESS")
name3 = Sashite::Snn.parse("chess")
name1 == name2 # => true
name1.hash == name2.hash # => true
name1 == name3 # => false (different case = different player)Examples
Traditional Chess Family
# First player styles (uppercase)
chess = Sashite::Snn.parse("CHESS") # Western Chess
shogi = Sashite::Snn.parse("SHOGI") # Japanese Chess
xiangqi = Sashite::Snn.parse("XIANGQI") # Chinese Chess
makruk = Sashite::Snn.parse("MAKRUK") # Thai Chess
# Second player styles (lowercase)
chess_p2 = Sashite::Snn.parse("chess")
shogi_p2 = Sashite::Snn.parse("shogi")Historical Games
chaturanga = Sashite::Snn.parse("CHATURANGA") # Ancient Indian Chess
shatranj = Sashite::Snn.parse("SHATRANJ") # Medieval Islamic ChessModern Variants
raumschach = Sashite::Snn.parse("RAUMSCHACH") # 3D Chess
omega = Sashite::Snn.parse("OMEGA") # Omega ChessCase Consistency
# Valid - all uppercase
Sashite::Snn.valid?("CHESS") # => true
Sashite::Snn.valid?("XIANGQI") # => true
# Valid - all lowercase
Sashite::Snn.valid?("shogi") # => true
Sashite::Snn.valid?("makruk") # => true
# Invalid - mixed case
Sashite::Snn.valid?("Chess") # => false
Sashite::Snn.valid?("Shogi") # => false
Sashite::Snn.valid?("XiangQi") # => false
# Invalid - contains non-alphabetic characters
Sashite::Snn.valid?("CHESS960") # => false
Sashite::Snn.valid?("GO9X9") # => false
Sashite::Snn.valid?("MINI_SHOGI") # => falseWorking with Names
# Create and compare
name1 = Sashite::Snn.parse("SHOGI")
name2 = Sashite::Snn.parse("SHOGI")
name1 == name2 # => true
# String and symbol inputs
name1 = Sashite::Snn.name("XIANGQI")
name2 = Sashite::Snn.name(:XIANGQI)
name1 == name2 # => true
# Immutability
name = Sashite::Snn.parse("CHESS")
name.frozen? # => true
name.value.frozen? # => trueCollections
# Create a set of styles
styles = %w[CHESS SHOGI XIANGQI MAKRUK].map { |n| Sashite::Snn.parse(n) }
# Filter by prefix
styles.select { |s| s.value.start_with?("X") }.map(&:to_s)
# => ["XIANGQI"]
# Use in hash
style_map = {
Sashite::Snn.parse("CHESS") => "Western Chess",
Sashite::Snn.parse("SHOGI") => "Japanese Chess"
}Relationship with SIN
SNN and SIN are independent primitives that serve complementary roles:
-
SNN: Human-readable, descriptive names (
CHESS,SHOGI) -
SIN: Compact, single-character identification (
C,S)
Optional Correspondence
While both specifications can be used independently, they may be related through:
- Mapping tables: External context defining SNN ↔ SIN relationships
-
Case consistency: When mapped, case must be preserved (
CHESS↔C,chess↔c)
# Example mapping (defined externally, not part of SNN)
SNN_TO_SIN = {
"CHESS" => "C",
"chess" => "c",
"SHOGI" => "S",
"shogi" => "s"
}
# Multiple SNN names may map to the same SIN
SNN_TO_SIN["CAPABLANCA"] = "C" # Also maps to "C"
SNN_TO_SIN["COURIER"] = "C" # Also maps to "C"Important Notes
- No dependency: SNN does not depend on SIN, nor SIN on SNN
- Bidirectional mapping requires context: Converting between SNN and SIN requires external mapping information
- Independent usage: Systems may use SNN alone, SIN alone, or both with defined mappings
- Multiple mappings: One SNN name may correspond to multiple SIN characters in different contexts, and vice versa
Error Handling
begin
name = Sashite::Snn.parse("Chess960")
rescue ArgumentError => e
warn "Invalid SNN: #{e.message}"
# => "Invalid SNN string: \"Chess960\""
endCommon Errors
# Mixed case
Sashite::Snn.parse("Chess")
# => ArgumentError: Invalid SNN string: "Chess"
# Contains digits
Sashite::Snn.parse("CHESS960")
# => ArgumentError: Invalid SNN string: "CHESS960"
# Contains special characters
Sashite::Snn.parse("MINI_SHOGI")
# => ArgumentError: Invalid SNN string: "MINI_SHOGI"
# Empty string
Sashite::Snn.parse("")
# => ArgumentError: Invalid SNN string: ""Design Principles
- Human-readable: Descriptive names for better usability
- Case-consistent: Visual distinction between players through case
- Foundational primitive: Serves as building block for formal style identification
- Rule-agnostic: Independent of specific game mechanics
- Self-contained: No external dependencies
- Immutable: All objects are frozen and thread-safe
- Canonical: Each style has one valid representation per context
Properties
- Purely functional: Immutable data structures, no side effects
- Specification compliant: Strict adherence to SNN v1.0.0
- Minimal API: Simple validation, parsing, and comparison
- Universal: Supports any abstract strategy board game style
- No dependencies: Foundational primitive requiring no external gems
Documentation
- SNN Specification v1.0.0 — Complete technical specification
- SNN Examples — Comprehensive examples
- API Documentation — Full API reference
Development
# Clone the repository
git clone https://github.com/sashite/snn.rb.git
cd snn.rb
# Install dependencies
bundle install
# Run tests
ruby test.rb
# Generate documentation
yard docContributing
- Fork the repository
- Create a feature branch (
git checkout -b feature/new-feature) - Add tests for your changes
- Ensure all tests pass (
ruby test.rb) - Commit your changes (
git commit -am 'Add new feature') - Push to the branch (
git push origin feature/new-feature) - Create a Pull Request
License
Available as open source under the MIT License.
About
Maintained by Sashité — promoting chess variants and sharing the beauty of board game cultures.