sashite-gan 3.0.0 → 5.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 +4 -4
- data/README.md +623 -95
- data/lib/sashite/gan/actor.rb +507 -0
- data/lib/sashite/gan.rb +57 -57
- data/lib/sashite-gan.rb +10 -3
- metadata +29 -14
- data/lib/sashite/gan/dumper.rb +0 -94
- data/lib/sashite/gan/parser.rb +0 -58
- data/lib/sashite/gan/validator.rb +0 -23
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sashite-gan
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 5.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cyril Kato
|
@@ -10,23 +10,40 @@ cert_chain: []
|
|
10
10
|
date: 1980-01-02 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
|
-
name:
|
13
|
+
name: sashite-pin
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
15
15
|
requirements:
|
16
16
|
- - "~>"
|
17
17
|
- !ruby/object:Gem::Version
|
18
|
-
version:
|
18
|
+
version: 2.0.2
|
19
19
|
type: :runtime
|
20
20
|
prerelease: false
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
22
22
|
requirements:
|
23
23
|
- - "~>"
|
24
24
|
- !ruby/object:Gem::Version
|
25
|
-
version:
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
25
|
+
version: 2.0.2
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: sashite-snn
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - "~>"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 1.1.1
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: 1.1.1
|
40
|
+
description: 'A Ruby implementation of GAN (General Actor Notation) v1.0.0 specification
|
41
|
+
for identifying game actors in abstract strategy board games. GAN combines Style
|
42
|
+
Name Notation (SNN) and Piece Identifier Notation (PIN) with a colon separator to
|
43
|
+
provide complete, unambiguous piece identification. Represents all four fundamental
|
44
|
+
piece attributes: Type, Side, State, and Style. Enables cross-style gaming, immutable
|
45
|
+
transformations, and component extraction with to_pin/to_snn methods. Built on sashite-snn
|
46
|
+
and sashite-pin gems.'
|
30
47
|
email: contact@cyril.email
|
31
48
|
executables: []
|
32
49
|
extensions: []
|
@@ -36,9 +53,7 @@ files:
|
|
36
53
|
- README.md
|
37
54
|
- lib/sashite-gan.rb
|
38
55
|
- lib/sashite/gan.rb
|
39
|
-
- lib/sashite/gan/
|
40
|
-
- lib/sashite/gan/parser.rb
|
41
|
-
- lib/sashite/gan/validator.rb
|
56
|
+
- lib/sashite/gan/actor.rb
|
42
57
|
homepage: https://github.com/sashite/gan.rb
|
43
58
|
licenses:
|
44
59
|
- MIT
|
@@ -47,7 +62,7 @@ metadata:
|
|
47
62
|
documentation_uri: https://rubydoc.info/github/sashite/gan.rb/main
|
48
63
|
homepage_uri: https://github.com/sashite/gan.rb
|
49
64
|
source_code_uri: https://github.com/sashite/gan.rb
|
50
|
-
specification_uri: https://sashite.dev/
|
65
|
+
specification_uri: https://sashite.dev/specs/gan/1.0.0/
|
51
66
|
rubygems_mfa_required: 'true'
|
52
67
|
rdoc_options: []
|
53
68
|
require_paths:
|
@@ -63,7 +78,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
63
78
|
- !ruby/object:Gem::Version
|
64
79
|
version: '0'
|
65
80
|
requirements: []
|
66
|
-
rubygems_version: 3.6.
|
81
|
+
rubygems_version: 3.6.9
|
67
82
|
specification_version: 4
|
68
|
-
summary: GAN (General Actor Notation)
|
83
|
+
summary: GAN (General Actor Notation) implementation for Ruby - board game piece identification
|
69
84
|
test_files: []
|
data/lib/sashite/gan/dumper.rb
DELETED
@@ -1,94 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "pnn"
|
4
|
-
|
5
|
-
module Sashite
|
6
|
-
module Gan
|
7
|
-
# Serializes actor components into GAN (General Actor Notation) strings.
|
8
|
-
#
|
9
|
-
# The dumper transforms piece data and game identifiers into properly
|
10
|
-
# formatted GAN strings, ensuring consistency between game ID casing
|
11
|
-
# and piece letter casing according to the GAN specification.
|
12
|
-
#
|
13
|
-
# According to the specification, game IDs must be either all uppercase
|
14
|
-
# or all lowercase, and their casing must match the casing of the piece letter.
|
15
|
-
class Dumper
|
16
|
-
# Pattern for validating game identifiers - must be all uppercase OR all lowercase
|
17
|
-
GAME_ID_PATTERN = /\A([A-Z]+|[a-z]+)\z/
|
18
|
-
|
19
|
-
# Error message templates
|
20
|
-
INVALID_GAME_ID_ERROR = "Game ID must be a non-empty string containing only ASCII letters and must be either all uppercase or all lowercase: %s"
|
21
|
-
CASING_MISMATCH_ERROR = "Game ID casing (%s) must match piece letter casing (%s)"
|
22
|
-
|
23
|
-
# Serializes actor components into a GAN string
|
24
|
-
#
|
25
|
-
# @param game_id [String] The game identifier (e.g., "CHESS", "shogi")
|
26
|
-
# @param piece_params [Hash] Piece parameters as accepted by Pnn.dump:
|
27
|
-
# @option piece_params [String] :letter The single ASCII letter identifier (required)
|
28
|
-
# @option piece_params [String, nil] :prefix Optional prefix modifier for the piece ("+", "-")
|
29
|
-
# @option piece_params [String, nil] :suffix Optional suffix modifier for the piece ("'")
|
30
|
-
# @return [String] A properly formatted GAN notation string (e.g., "CHESS:K'")
|
31
|
-
# @raise [ArgumentError] If game_id is invalid or casing is inconsistent with piece letter
|
32
|
-
# @example Create a GAN string for a white chess king with castling rights
|
33
|
-
# Dumper.dump(game_id: "CHESS", letter: "K", suffix: "'")
|
34
|
-
# # => "CHESS:K'"
|
35
|
-
# @example Create a GAN string for a promoted shogi pawn
|
36
|
-
# Dumper.dump(game_id: "SHOGI", letter: "P", prefix: "+")
|
37
|
-
# # => "SHOGI:+P"
|
38
|
-
def self.dump(game_id:, **piece_params)
|
39
|
-
game_id = String(game_id)
|
40
|
-
validate_game_id!(game_id)
|
41
|
-
|
42
|
-
# Build the piece string using the PNN gem
|
43
|
-
pnn_string = ::Pnn.dump(**piece_params)
|
44
|
-
|
45
|
-
# Verify casing consistency
|
46
|
-
validate_casing_consistency!(game_id, pnn_string)
|
47
|
-
|
48
|
-
"#{game_id}:#{pnn_string}"
|
49
|
-
end
|
50
|
-
|
51
|
-
# @api private
|
52
|
-
# Validates that the game_id contains only ASCII letters
|
53
|
-
#
|
54
|
-
# @param game_id [String] The game identifier to validate
|
55
|
-
# @return [void]
|
56
|
-
# @raise [ArgumentError] If game_id contains non-letter characters
|
57
|
-
def self.validate_game_id!(game_id)
|
58
|
-
return if game_id.match?(GAME_ID_PATTERN)
|
59
|
-
|
60
|
-
raise ::ArgumentError, format(INVALID_GAME_ID_ERROR, game_id)
|
61
|
-
end
|
62
|
-
private_class_method :validate_game_id!
|
63
|
-
|
64
|
-
# @api private
|
65
|
-
# Validates that the casing of the game_id is consistent with the piece letter
|
66
|
-
#
|
67
|
-
# According to GAN specification, if game_id is uppercase, piece letter must be uppercase,
|
68
|
-
# and if game_id is lowercase, piece letter must be lowercase.
|
69
|
-
#
|
70
|
-
# @param game_id [String] The game identifier
|
71
|
-
# @param pnn_string [String] The PNN string
|
72
|
-
# @return [void]
|
73
|
-
# @raise [ArgumentError] If casing is inconsistent
|
74
|
-
def self.validate_casing_consistency!(game_id, pnn_string)
|
75
|
-
return if casing_consistent?(game_id, pnn_string)
|
76
|
-
|
77
|
-
raise ::ArgumentError, format(CASING_MISMATCH_ERROR, game_id, pnn_string)
|
78
|
-
end
|
79
|
-
private_class_method :validate_casing_consistency!
|
80
|
-
|
81
|
-
# @api private
|
82
|
-
# Verifies that the casing of the game_id matches the casing of the piece letter
|
83
|
-
#
|
84
|
-
# @param game_id [String] The game identifier
|
85
|
-
# @param pnn_string [String] The PNN string
|
86
|
-
# @return [Boolean] True if casing is consistent
|
87
|
-
def self.casing_consistent?(game_id, pnn_string)
|
88
|
-
# Both must be uppercase or both must be lowercase
|
89
|
-
(game_id == game_id.upcase) == (pnn_string == pnn_string.upcase)
|
90
|
-
end
|
91
|
-
private_class_method :casing_consistent?
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
data/lib/sashite/gan/parser.rb
DELETED
@@ -1,58 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "pnn"
|
4
|
-
|
5
|
-
module Sashite
|
6
|
-
module Gan
|
7
|
-
# Parses GAN strings into their component parts
|
8
|
-
class Parser
|
9
|
-
# GAN regex pattern for parsing
|
10
|
-
PATTERN = /\A(?<game_id>[a-zA-Z]+):(?<pnn_part>[-+]?[a-zA-Z][']?)\z/
|
11
|
-
|
12
|
-
# Parse a GAN string into its components
|
13
|
-
#
|
14
|
-
# @param gan_string [String] The GAN string to parse
|
15
|
-
# @return [Hash] Hash containing the parsed components
|
16
|
-
# @raise [ArgumentError] If the GAN string is invalid
|
17
|
-
def self.parse(gan_string)
|
18
|
-
gan_string = String(gan_string)
|
19
|
-
|
20
|
-
matches = PATTERN.match(gan_string)
|
21
|
-
raise ArgumentError, "Invalid GAN string: #{gan_string}" if matches.nil?
|
22
|
-
|
23
|
-
game_id = matches[:game_id]
|
24
|
-
pnn_part = matches[:pnn_part]
|
25
|
-
|
26
|
-
# Parse the PNN part using the PNN gem
|
27
|
-
pnn_result = Pnn.parse(pnn_part)
|
28
|
-
|
29
|
-
# Verify casing consistency
|
30
|
-
unless casing_consistent?(game_id, pnn_result[:letter])
|
31
|
-
raise ArgumentError, "Game ID casing (#{game_id}) must match piece letter casing (#{pnn_result[:letter]})"
|
32
|
-
end
|
33
|
-
|
34
|
-
# Merge the game_id with the piece parameters for a flatter structure
|
35
|
-
{ game_id: game_id }.merge(pnn_result)
|
36
|
-
end
|
37
|
-
|
38
|
-
# Safely parse a GAN string without raising exceptions
|
39
|
-
#
|
40
|
-
# @param gan_string [String] The GAN string to parse
|
41
|
-
# @return [Hash, nil] Hash containing the parsed components or nil if invalid
|
42
|
-
def self.safe_parse(gan_string)
|
43
|
-
parse(gan_string)
|
44
|
-
rescue ArgumentError
|
45
|
-
nil
|
46
|
-
end
|
47
|
-
|
48
|
-
# Verifies that the casing of the game_id matches the casing of the piece letter
|
49
|
-
#
|
50
|
-
# @param game_id [String] The game identifier
|
51
|
-
# @param letter [String] The piece letter
|
52
|
-
# @return [Boolean] True if casing is consistent
|
53
|
-
def self.casing_consistent?(game_id, letter)
|
54
|
-
(game_id == game_id.upcase) == (letter == letter.upcase)
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
@@ -1,23 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "pnn"
|
4
|
-
|
5
|
-
module Sashite
|
6
|
-
module Gan
|
7
|
-
# Validates GAN strings
|
8
|
-
class Validator
|
9
|
-
# GAN regex pattern for validation
|
10
|
-
PATTERN = /\A([A-Z]+:[-+]?[A-Z][']?|[a-z]+:[-+]?[a-z][']?)\z/
|
11
|
-
|
12
|
-
# Validates if the given string is a valid GAN string
|
13
|
-
#
|
14
|
-
# @param gan_string [String] The GAN string to validate
|
15
|
-
# @return [Boolean] True if the string is a valid GAN string
|
16
|
-
def self.valid?(gan_string)
|
17
|
-
return false unless gan_string.is_a?(String)
|
18
|
-
|
19
|
-
PATTERN.match?(gan_string)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|