SIN (Style Identifier Notation) implementation for Elixir.
This library implements the SIN Specification v1.0.0.
Add sashite_sin to your list of dependencies in mix.exs:
def deps do
[
{:sashite_sin, "~> 2.0"}
]
endConvert a SIN string into an Identifier struct.
alias Sashite.Sin.Identifier
# Standard parsing (returns {:ok, _} or {:error, _})
{:ok, sin} = Sashite.Sin.parse("C")
sin.style # => :C
sin.side # => :first
# Lowercase indicates second player
{:ok, sin} = Sashite.Sin.parse("c")
sin.style # => :C
sin.side # => :second
# Bang version (raises on error)
sin = Sashite.Sin.parse!("C")
# Invalid input returns error tuple
{:error, :empty_input} = Sashite.Sin.parse("")
{:error, :input_too_long} = Sashite.Sin.parse("CC")Convert an Identifier back to a SIN string.
alias Sashite.Sin.Identifier
# From Identifier struct
sin = Identifier.new(:C, :first)
Identifier.to_string(sin) # => "C"
sin = Identifier.new(:C, :second)
Identifier.to_string(sin) # => "c"# Boolean check
Sashite.Sin.valid?("C") # => true
Sashite.Sin.valid?("c") # => true
Sashite.Sin.valid?("") # => false
Sashite.Sin.valid?("CC") # => false
Sashite.Sin.valid?("1") # => falsesin = Sashite.Sin.parse!("C")
# Get attributes (struct fields)
sin.style # => :C
sin.side # => :first
# Get string component
Sashite.Sin.Identifier.letter(sin) # => "C"All transformations return new immutable Identifier structs.
alias Sashite.Sin.Identifier
sin = Sashite.Sin.parse!("C")
# Side transformation
Identifier.flip(sin) |> Identifier.to_string() # => "c"
# Attribute changes
Identifier.with_style(sin, :S) |> Identifier.to_string() # => "S"
Identifier.with_side(sin, :second) |> Identifier.to_string() # => "c"alias Sashite.Sin.Identifier
sin = Sashite.Sin.parse!("C")
# Side queries
Identifier.first_player?(sin) # => true
Identifier.second_player?(sin) # => false
# Comparison queries
other = Sashite.Sin.parse!("c")
Identifier.same_style?(sin, other) # => true
Identifier.same_side?(sin, other) # => false# Identifier represents a parsed SIN identifier with style and side.
%Sashite.Sin.Identifier{
style: :A..:Z, # Piece style (always uppercase atom)
side: :first | :second # Player side
}
# Create an Identifier from style and side.
# Raises ArgumentError if attributes are invalid.
Sashite.Sin.Identifier.new(style, side)Sashite.Sin.Constants.valid_styles() # => [:A, :B, ..., :Z]
Sashite.Sin.Constants.valid_sides() # => [:first, :second]
Sashite.Sin.Constants.max_string_length() # => 1# Parses a SIN string into an Identifier.
# Returns {:ok, identifier} or {:error, reason}.
@spec Sashite.Sin.parse(String.t()) :: {:ok, Identifier.t()} | {:error, atom()}
# Parses a SIN string into an Identifier.
# Raises ArgumentError if the string is not valid.
@spec Sashite.Sin.parse!(String.t()) :: Identifier.t()# Reports whether string is a valid SIN identifier.
@spec Sashite.Sin.valid?(String.t()) :: boolean()All transformations return new Sashite.Sin.Identifier structs:
# Side transformation
@spec Identifier.flip(Identifier.t()) :: Identifier.t()
# Attribute changes
@spec Identifier.with_style(Identifier.t(), atom()) :: Identifier.t()
@spec Identifier.with_side(Identifier.t(), atom()) :: Identifier.t()# Side queries
@spec Identifier.first_player?(Identifier.t()) :: boolean()
@spec Identifier.second_player?(Identifier.t()) :: boolean()
# Comparison queries
@spec Identifier.same_style?(Identifier.t(), Identifier.t()) :: boolean()
@spec Identifier.same_side?(Identifier.t(), Identifier.t()) :: boolean()Parsing errors are returned as atoms:
| Atom | Cause |
|---|---|
:empty_input |
String length is 0 |
:input_too_long |
String exceeds 1 character |
:must_be_letter |
Character is not A-Z or a-z |
- Bounded values: Explicit validation of styles and sides
- Struct-based:
Identifierstruct enables pattern matching and encapsulation - Elixir idioms:
{:ok, _}/{:error, _}tuples,parse!bang variant - Immutable data: All transformations return new structs
- No dependencies: Pure Elixir standard library only
- Game Protocol — Conceptual foundation
- SIN Specification — Official specification
- SIN Examples — Usage examples
Available as open source under the Apache License 2.0.