sashite-ggn 0.7.0 → 0.8.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 +300 -562
- data/lib/sashite/ggn/ruleset/source/destination/engine.rb +120 -309
- data/lib/sashite/ggn/ruleset/source/destination.rb +46 -84
- data/lib/sashite/ggn/ruleset/source.rb +40 -73
- data/lib/sashite/ggn/ruleset.rb +183 -403
- data/lib/sashite/ggn.rb +47 -334
- data/lib/sashite-ggn.rb +8 -120
- metadata +96 -20
- data/lib/sashite/ggn/move_validator.rb +0 -208
- data/lib/sashite/ggn/ruleset/source/destination/engine/transition.rb +0 -81
- data/lib/sashite/ggn/schema.rb +0 -171
- data/lib/sashite/ggn/validation_error.rb +0 -56
@@ -1,97 +1,64 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
4
|
-
require_relative File.join("source", "destination")
|
3
|
+
require_relative "source/destination"
|
5
4
|
|
6
5
|
module Sashite
|
7
6
|
module Ggn
|
8
7
|
class Ruleset
|
9
|
-
# Represents
|
8
|
+
# Represents movement possibilities for a piece type
|
10
9
|
#
|
11
|
-
#
|
12
|
-
# a piece can move on the board. Since GGN focuses exclusively on
|
13
|
-
# board-to-board transformations, all source positions are regular
|
14
|
-
# board squares.
|
15
|
-
#
|
16
|
-
# @example Basic usage with chess king
|
17
|
-
# piece_data = Sashite::Ggn.load_file('chess.json')
|
18
|
-
# source = piece_data.select('CHESS:K')
|
19
|
-
# destinations = source.from('e1')
|
20
|
-
#
|
21
|
-
# @example Complete move evaluation workflow
|
22
|
-
# piece_data = Sashite::Ggn.load_file('chess.json')
|
23
|
-
# king_source = piece_data.select('CHESS:K')
|
24
|
-
# destinations = king_source.from('e1')
|
25
|
-
# engine = destinations.to('e2')
|
26
|
-
#
|
27
|
-
# board_state = { 'e1' => 'CHESS:K', 'e2' => nil }
|
28
|
-
# transitions = engine.where(board_state, 'CHESS')
|
29
|
-
#
|
30
|
-
# if transitions.any?
|
31
|
-
# puts "King can move from e1 to e2"
|
32
|
-
# end
|
10
|
+
# @see https://sashite.dev/specs/ggn/1.0.0/
|
33
11
|
class Source
|
34
|
-
|
12
|
+
# @return [String] The QPI piece identifier
|
13
|
+
attr_reader :piece
|
35
14
|
|
36
|
-
#
|
37
|
-
|
38
|
-
# @param data [Hash] The movement data where keys are source positions
|
39
|
-
# (square labels) and values contain destination data.
|
40
|
-
# @param actor [String] The GAN identifier for this piece type
|
41
|
-
#
|
42
|
-
# @raise [ArgumentError] If data is not a Hash
|
43
|
-
#
|
44
|
-
# @example Creating a Source instance
|
45
|
-
# source_data = {
|
46
|
-
# "e1" => { "e2" => [...], "f1" => [...] },
|
47
|
-
# "d4" => { "d5" => [...], "e5" => [...] }
|
48
|
-
# }
|
49
|
-
# source = Source.new(source_data, actor: "CHESS:K")
|
50
|
-
def initialize(data, actor:)
|
51
|
-
raise ::ArgumentError, "Expected Hash, got #{data.class}" unless data.is_a?(::Hash)
|
15
|
+
# @return [Hash] The sources data
|
16
|
+
attr_reader :data
|
52
17
|
|
18
|
+
# Create a new Source
|
19
|
+
#
|
20
|
+
# @param piece [String] QPI piece identifier
|
21
|
+
# @param data [Hash] Sources data structure
|
22
|
+
def initialize(piece, data)
|
23
|
+
@piece = piece
|
53
24
|
@data = data
|
54
|
-
@actor = actor
|
55
25
|
|
56
26
|
freeze
|
57
27
|
end
|
58
28
|
|
59
|
-
#
|
29
|
+
# Specify the source location for the piece
|
60
30
|
#
|
61
|
-
# @param
|
62
|
-
#
|
31
|
+
# @param source [String] Source location (CELL coordinate or HAND "*")
|
32
|
+
# @return [Destination] Destination selector object
|
33
|
+
# @raise [KeyError] If source not found for this piece
|
63
34
|
#
|
64
|
-
# @
|
65
|
-
#
|
35
|
+
# @example
|
36
|
+
# destination = source.from("e1")
|
37
|
+
def from(source)
|
38
|
+
raise ::KeyError, "Source not found: #{source}" unless source?(source)
|
39
|
+
|
40
|
+
Destination.new(piece, source, data.fetch(source))
|
41
|
+
end
|
42
|
+
|
43
|
+
# Return all valid source locations for this piece
|
66
44
|
#
|
67
|
-
# @
|
45
|
+
# @return [Array<String>] Source locations
|
68
46
|
#
|
69
|
-
# @example
|
70
|
-
#
|
71
|
-
|
47
|
+
# @example
|
48
|
+
# source.sources # => ["e1", "d1", "*"]
|
49
|
+
def sources
|
50
|
+
data.keys
|
51
|
+
end
|
52
|
+
|
53
|
+
# Check if location is a valid source for this piece
|
72
54
|
#
|
73
|
-
# @
|
74
|
-
#
|
75
|
-
# destinations = source.from('invalid_square')
|
76
|
-
# rescue KeyError => e
|
77
|
-
# puts "No moves from this position: #{e.message}"
|
78
|
-
# end
|
55
|
+
# @param location [String] Source location
|
56
|
+
# @return [Boolean]
|
79
57
|
#
|
80
|
-
# @example
|
81
|
-
# #
|
82
|
-
|
83
|
-
|
84
|
-
# begin
|
85
|
-
# destinations = source.from(pos)
|
86
|
-
# puts "Piece can move from #{pos}"
|
87
|
-
# # Process destinations...
|
88
|
-
# rescue KeyError
|
89
|
-
# puts "No moves available from #{pos}"
|
90
|
-
# end
|
91
|
-
# end
|
92
|
-
def from(origin)
|
93
|
-
data = @data.fetch(origin)
|
94
|
-
Destination.new(data, actor: @actor, origin: origin)
|
58
|
+
# @example
|
59
|
+
# source.source?("e1") # => true
|
60
|
+
def source?(location)
|
61
|
+
data.key?(location)
|
95
62
|
end
|
96
63
|
end
|
97
64
|
end
|