# Sashite.Sin
[](https://hex.pm/packages/sashite_sin)
[](https://hexdocs.pm/sashite_sin)
[](https://github.com/sashite/sin.ex/blob/main/LICENSE.md)
> **SIN** (Style Identifier Notation) implementation for Elixir.
## What is SIN?
SIN (Style Identifier Notation) provides a compact, ASCII-based format for encoding **Piece Style** with an associated **Side** in abstract strategy board games. It serves as a minimal building block that can be embedded in higher-level notations.
This library implements the [SIN Specification v1.0.0](https://sashite.dev/specs/sin/1.0.0/).
## Installation
Add `sashite_sin` to your list of dependencies in `mix.exs`:
```elixir
def deps do
[
{:sashite_sin, "~> 1.0"}
]
end
```
## Usage
```elixir
# Parse SIN strings
{:ok, sin} = Sashite.Sin.parse("C")
sin.style # => :C
sin.side # => :first
Sashite.Sin.to_string(sin) # => "C"
# Parse with pattern matching
{:ok, chess_first} = Sashite.Sin.parse("C") # Chess-style, first player
{:ok, chess_second} = Sashite.Sin.parse("c") # Chess-style, second player
{:ok, shogi_first} = Sashite.Sin.parse("S") # Shogi-style, first player
# Bang version for direct access
sin = Sashite.Sin.parse!("C")
# Create identifiers directly
sin = Sashite.Sin.new(:C, :first)
sin = Sashite.Sin.new(:S, :second)
# Validation
Sashite.Sin.valid?("C") # => true
Sashite.Sin.valid?("s") # => true
Sashite.Sin.valid?("CC") # => false (more than one character)
Sashite.Sin.valid?("1") # => false (digit instead of letter)
Sashite.Sin.valid?("") # => false (empty string)
# Side transformation
flipped = Sashite.Sin.flip(sin)
Sashite.Sin.to_string(flipped) # => "c"
# Attribute changes
shogi = Sashite.Sin.with_style(sin, :S)
Sashite.Sin.to_string(shogi) # => "S"
second = Sashite.Sin.with_side(sin, :second)
Sashite.Sin.to_string(second) # => "c"
# Side queries
Sashite.Sin.first_player?(sin) # => true
Sashite.Sin.second_player?(sin) # => false
# Comparison
chess1 = Sashite.Sin.parse!("C")
chess2 = Sashite.Sin.parse!("c")
Sashite.Sin.same_style?(chess1, chess2) # => true
Sashite.Sin.same_side?(chess1, chess2) # => false
```
## Format Specification
### Structure
```
<letter>
```
A SIN token is **exactly one** ASCII letter (`A-Z` or `a-z`).
### Attribute Mapping
| Attribute | Encoding |
|-----------|----------|
| Piece Style | Base letter (case-insensitive): `C` and `c` represent the same style |
| Side | Letter case: uppercase → `first`, lowercase → `second` |
### Side Convention
- **Uppercase** (`A-Z`): First player (Side `first`)
- **Lowercase** (`a-z`): Second player (Side `second`)
### Common Conventions
| SIN | Side | Typical Piece Style |
|-----|------|---------------------|
| `C` | First | Chess-style |
| `c` | Second | Chess-style |
| `S` | First | Shogi-style |
| `s` | Second | Shogi-style |
| `X` | First | Xiangqi-style |
| `x` | Second | Xiangqi-style |
| `M` | First | Makruk-style |
| `m` | Second | Makruk-style |
### Invalid Token Examples
| String | Reason |
|--------|--------|
| `""` | Empty string |
| `CC` | More than one character |
| `c1` | Contains a digit |
| `+C` | Contains a prefix character |
| ` C` | Leading whitespace |
| `C ` | Trailing whitespace |
| `1` | Digit instead of letter |
| `é` | Non-ASCII character |
## API Reference
### Parsing
```elixir
Sashite.Sin.parse(sin_string) # => {:ok, %Sashite.Sin{}} | {:error, reason}
Sashite.Sin.parse!(sin_string) # => %Sashite.Sin{} | raises ArgumentError
Sashite.Sin.valid?(sin_string) # => boolean
```
### Creation
```elixir
Sashite.Sin.new(style, side)
```
### Conversion
```elixir
Sashite.Sin.to_string(sin) # => String.t()
Sashite.Sin.letter(sin) # => String.t() (the single character)
```
### Transformations
All transformations return new `%Sashite.Sin{}` structs:
```elixir
# Side
Sashite.Sin.flip(sin)
# Attribute changes
Sashite.Sin.with_style(sin, new_style)
Sashite.Sin.with_side(sin, new_side)
```
### Queries
```elixir
# Side
Sashite.Sin.first_player?(sin)
Sashite.Sin.second_player?(sin)
# Comparison
Sashite.Sin.same_style?(sin1, sin2)
Sashite.Sin.same_side?(sin1, sin2)
```
## Data Structure
```elixir
%Sashite.Sin{
style: :A..:Z, # Piece style (always uppercase atom)
side: :first | :second # Player side
}
```
## Protocol Mapping
Following the [Game Protocol](https://sashite.dev/game-protocol/):
| Protocol Attribute | SIN Encoding |
|-------------------|--------------|
| Piece Style | Base letter (case-insensitive) |
| Side | Letter case |
## Relationship with SNN
**Style Name Notation (SNN)** and SIN are **independent primitives** that serve complementary roles:
- **SIN** — compact, single-character style identifiers (`C`, `s`, `X`)
- **SNN** — human-readable style names (`CHESS`, `shogi`, `XIANGQI`)
Converting between SIN and SNN requires external, context-specific mapping.
## Related Specifications
- [Game Protocol](https://sashite.dev/game-protocol/) — Conceptual foundation
- [PIN](https://sashite.dev/specs/pin/1.0.0/) — Piece Identifier Notation
- [SIN Specification](https://sashite.dev/specs/sin/1.0.0/) — Official specification
## License
Available as open source under the [MIT License](https://opensource.org/licenses/MIT).
## About
Maintained by [Sashité](https://sashite.com/) — promoting chess variants and sharing the beauty of board game cultures.