qi 10.0.0.beta11 → 10.0.0.beta12

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +38 -27
  3. data/lib/qi.rb +74 -211
  4. metadata +20 -6
  5. data/lib/qi/error/drop.rb +0 -13
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 79ffab5e654d14cf9f3f7dac1c50bc5b5c612452d0fdea35a00d3529337fbff2
4
- data.tar.gz: b8fecf9ff5dd97923070809b6a906c8b44cebbee9695ea242e314d53afb9fad8
3
+ metadata.gz: 7f3a609bb51c87ae5486c9244b948899f4e6ae46747ac80bf3be5f83ae76826a
4
+ data.tar.gz: 1843fa6cc35f2dcaaab08a7772abeb9f56fa3e7d0dc5dc69f9a742ec47e81169
5
5
  SHA512:
6
- metadata.gz: cb36bd477ba3e756b116e3f2ab55bdb15ea50834461cc614865d8fdda56e271eff4675d998172bd766b8ca33e6944be3bbf567a1eba96b6215816234c485f6c9
7
- data.tar.gz: e56b5f73bf2c0a1a3a256f813acfcf24af3bc3cdd570f2fb6ab1aa2f7ebc194ddd0b82e5ade5cbc052229377a8c768d3f49f45188d811a756ab7781481c69f08
6
+ metadata.gz: f79f7dc430f3e84b5cf816492c4f31c7776db329fffd18e161df929ccf18cb85b37cdd69e35c2b93da0e983e976d765bf69e8a33f1e946ec62d61c7b5583d164
7
+ data.tar.gz: '059b84b8c426af80188f0b6885ff921ab86f7015756d5309d75fd0ab621f1d93322be5f83f603a02535850645da432219af815871c480b56dec0e8f67db738bb'
data/README.md CHANGED
@@ -6,14 +6,25 @@
6
6
  [![RuboCop](https://github.com/sashite/qi.rb/workflows/RuboCop/badge.svg?branch=main)](https://github.com/sashite/qi.rb/actions?query=workflow%3Arubocop+branch%3Amain)
7
7
  [![License](https://img.shields.io/github/license/sashite/qi.rb?label=License&logo=github)](https://github.com/sashite/qi.rb/raw/main/LICENSE.md)
8
8
 
9
- > `Qi` (Chinese: 棋; pinyin: _qí_) is an abstraction that could help to update positions for games like Shogi.
9
+ Welcome to `Qi` (Chinese: 棋; pinyin: _qí_), a flexible and customizable library designed to represent and manipulate board game positions. `Qi` is ideal for a variety of board games, including chess, shogi, xiangqi, makruk, and more.
10
+
11
+ With `Qi`, you can easily track the game state, including which pieces are on the board and where, as well as any captured pieces. The library allows for the application of game moves, updating the state of the game and generating a new position, all while preserving the original state.
12
+
13
+ ## Features:
14
+
15
+ - **Flexible representation of game states:** `Qi`'s design allows it to adapt to different games with varying rules and pieces.
16
+ - **Immutable positions:** Every move generates a new position, preserving the original one. This is particularly useful for scenarios like undoing moves or exploring potential future states in the game.
17
+ - **Compact serialization:** `Qi` provides a compact string serialization method for game states, which is useful for saving game progress or transmitting game states over the network.
18
+ - **Check state tracking:** In addition to the positions and captured pieces, `Qi` also allows tracking of specific game states such as check in chess.
19
+
20
+ While `Qi` does not generate game moves itself, it serves as a solid foundation upon which game engines can be built. Its design is focused on providing a robust and adaptable representation of game states, paving the way for the development of diverse board game applications.
10
21
 
11
22
  ## Installation
12
23
 
13
24
  Add this line to your application's Gemfile:
14
25
 
15
26
  ```ruby
16
- gem "qi", ">= 10.0.0.beta11"
27
+ gem "qi", ">= 10.0.0.beta12"
17
28
  ```
18
29
 
19
30
  And then execute:
@@ -33,42 +44,42 @@ gem install qi --pre
33
44
  ```ruby
34
45
  require "qi"
35
46
 
36
- is_north_turn = false
37
47
  north_captures = %w[r r b g g g g s n n n n p p p p p p p p p p p p p p p p p]
38
48
  south_captures = %w[S]
49
+ captures = north_captures + south_captures
39
50
  squares = { 3 => "s", 4 => "k", 5 => "s", 22 => "+P", 43 => "+B" }
40
51
 
41
- qi0 = Qi.new(is_north_turn, north_captures, south_captures, squares)
52
+ qi0 = Qi.new(*captures, **squares)
42
53
 
43
- qi0.north_captures # => ["b", "g", "g", "g", "g", "n", "n", "n", "n", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "r", "r", "s"]
44
- qi0.south_captures # => ["S"]
45
- qi0.squares # => {3=>"s", 4=>"k", 5=>"s", 22=>"+P", 43=>"+B"}
46
- qi0.north_turn? # => false
47
- qi0.south_turn? # => true
48
- qi0.serialize # => "South-turn===b,g,g,g,g,n,n,n,n,p,p,p,p,p,p,p,p,p,p,p,p,p,p,p,p,p,r,r,s,S===3:s,4:k,5:s,22:+P,43:+B"
49
- qi0.inspect # => "<Qi South-turn===b,g,g,g,g,n,n,n,n,p,p,p,p,p,p,p,p,p,p,p,p,p,p,p,p,p,r,r,s,S===3:s,4:k,5:s,22:+P,43:+B>"
54
+ qi0.captures # => ["S", "b", "g", "g", "g", "g", "n", "n", "n", "n", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "r", "r", "s"]
55
+ qi0.squares # => {3=>"s", 4=>"k", 5=>"s", 22=>"+P", 43=>"+B"}
56
+ qi0.in_check? # => false
57
+ qi0.not_in_check? # => true
58
+ qi0.north_turn? # => false
59
+ qi0.south_turn? # => true
60
+ qi0.serialize # => "{ S;b;g;g;g;g;n;n;n;n;p;p;p;p;p;p;p;p;p;p;p;p;p;p;p;p;p;r;r;s s@3;k@4;s@5;+P@22;+B@43 ."
61
+ qi0.inspect # => "<Qi { S;b;g;g;g;g;n;n;n;n;p;p;p;p;p;p;p;p;p;p;p;p;p;p;p;p;p;r;r;s s@3;k@4;s@5;+P@22;+B@43 .>"
50
62
  qi0.to_a
51
63
  # [false,
52
- # ["b", "g", "g", "g", "g", "n", "n", "n", "n", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "r", "r", "s"],
53
- # ["S"],
64
+ # ["S", "b", "g", "g", "g", "g", "n", "n", "n", "n", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "r", "r", "s"],
54
65
  # {3=>"s", 4=>"k", 5=>"s", 22=>"+P", 43=>"+B"},
55
- # {}]
56
-
57
- qi1 = qi0.commit(43, 13, "+B", nil)
58
-
59
- qi1.north_captures # => ["b", "g", "g", "g", "g", "n", "n", "n", "n", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "r", "r", "s"]
60
- qi1.south_captures # => ["S"]
61
- qi1.squares # => {3=>"s", 4=>"k", 5=>"s", 22=>"+P", 13=>"+B"}
62
- qi1.north_turn? # => true
63
- qi1.south_turn? # => false
64
- qi1.serialize # => "North-turn===b,g,g,g,g,n,n,n,n,p,p,p,p,p,p,p,p,p,p,p,p,p,p,p,p,p,r,r,s,S===3:s,4:k,5:s,13:+B,22:+P"
65
- qi1.inspect # => "<Qi North-turn===b,g,g,g,g,n,n,n,n,p,p,p,p,p,p,p,p,p,p,p,p,p,p,p,p,p,r,r,s,S===3:s,4:k,5:s,13:+B,22:+P>"
66
+ # false]
67
+
68
+ qi1 = qi0.commit(is_in_check: true, 43 => nil, 13 => "+B")
69
+
70
+ qi1.captures # => ["S", "b", "g", "g", "g", "g", "n", "n", "n", "n", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "r", "r", "s"]
71
+ qi1.squares # => {3=>"s", 4=>"k", 5=>"s", 22=>"+P", 13=>"+B"}
72
+ qi1.in_check? # => true
73
+ qi1.not_in_check? # => false
74
+ qi1.north_turn? # => true
75
+ qi1.south_turn? # => false
76
+ qi1.serialize # => "} S;b;g;g;g;g;n;n;n;n;p;p;p;p;p;p;p;p;p;p;p;p;p;p;p;p;p;r;r;s s@3;k@4;s@5;+B@13;+P@22 +"
77
+ qi1.inspect # => "<Qi } S;b;g;g;g;g;n;n;n;n;p;p;p;p;p;p;p;p;p;p;p;p;p;p;p;p;p;r;r;s s@3;k@4;s@5;+B@13;+P@22 +>"
66
78
  qi1.to_a
67
79
  # [true,
68
- # ["b", "g", "g", "g", "g", "n", "n", "n", "n", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "r", "r", "s"],
69
- # ["S"],
80
+ # ["S", "b", "g", "g", "g", "g", "n", "n", "n", "n", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "r", "r", "s"],
70
81
  # {3=>"s", 4=>"k", 5=>"s", 22=>"+P", 13=>"+B"},
71
- # {}]
82
+ # true]
72
83
  ```
73
84
 
74
85
  ## License
data/lib/qi.rb CHANGED
@@ -1,269 +1,132 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "digest"
4
- require_relative "qi/error/drop"
4
+ require "kernel/boolean"
5
5
 
6
- # Qi is a class for representing a state of games like Shogi. It includes
7
- # information about the current turn, captures, game board, and other game options.
6
+ # The Qi class represents a state of games such as Shogi.
8
7
  class Qi
9
- # Constants for representing the North and South players.
10
- North = :North
11
- South = :South
8
+ # @return [Array] the pieces captured by the current player.
9
+ attr_reader :captures
12
10
 
13
- # @return [Array] the pieces captured by the north player
14
- attr_reader :north_captures
15
-
16
- # @return [Array] the pieces captured by the south player
17
- attr_reader :south_captures
18
-
19
- # @return [Hash] the current state of the game board
11
+ # @return [Hash] the current state of the board.
20
12
  attr_reader :squares
21
13
 
22
- # @return [Hash] additional game options
23
- attr_reader :options
24
-
25
- # Initialize a new Qi object.
26
- #
27
- # @example Creating a new Qi object
28
- # qi = Qi.new(true, ['P', 'G'], ['B', '+B'], {56 => 'P', 3 => 'g', 64 => '+B'}, fullmove_number: 42, is_in_check: false)
29
- #
30
- # @param [Boolean] is_north_turn true if it's the north player's turn, false otherwise
31
- # @param [Array] north_captures the pieces captured by the north player
32
- # @param [Array] south_captures the pieces captured by the south player
33
- # @param [Hash] squares the current state of the game board
34
- # @param [Hash] options additional game options
35
- def initialize(is_north_turn, north_captures, south_captures, squares, **options)
36
- @is_north_turn = is_north_turn
37
- @north_captures = north_captures.sort
38
- @south_captures = south_captures.sort
14
+ # Initializes a new game state.
15
+ #
16
+ # @param capture [String, nil] the piece to be captured.
17
+ # @param captures [Array] the pieces already captured.
18
+ # @param drop [String, nil] the piece to be dropped.
19
+ # @param is_in_check [Boolean] whether the current player is in check.
20
+ # @param is_north_turn [Boolean] whether it's North's turn.
21
+ # @param squares [Hash] the current state of the board.
22
+ def initialize(capture = nil, *captures, drop: nil, is_in_check: false, is_north_turn: false, **squares)
23
+ captures << capture unless capture.nil?
24
+ captures.delete_at(captures.rindex(drop)) unless drop.nil?
25
+
26
+ @captures = captures.sort
27
+ @is_in_check = Boolean(is_in_check)
28
+ @is_north_turn = Boolean(is_north_turn)
39
29
  @squares = squares.compact
40
- @options = options
41
30
  end
42
31
 
43
- # Apply a move or a drop on the board.
44
- #
45
- # The method creates a new instance of Qi representing the state of the game after the move.
46
- # This includes updating the captures and the positions of the pieces on the board.
47
- #
48
- # @param src_square [Object, nil] the source square, or nil if dropping a piece from hand
49
- # @param dst_square [Object] the destination square
50
- # @param piece_name [String] the name of the piece to move
51
- # @param in_hand [String, nil] the piece in hand, or nil if moving a piece from a square
52
- # @param options [Hash] options to pass to the new instance
53
- #
54
- # @example Applying a move
55
- # qi = Qi.new(true, ['P', 'B'], ['G', '+B'], {56 => 'P', 64 => '+B'})
56
- # qi.commit(56, 47, 'P', nil) #=> <Qi South-turn===B,P,+B,G===47:P,64:+B>
57
- #
58
- # @example Applying a capture
59
- # qi = Qi.new(true, ['P', 'B'], ['G', '+B'], {56 => 'P', 64 => '+B'})
60
- # qi.commit(56, 47, 'P', 'G') #=> <Qi South-turn===B,G,P,+B,G===47:P,64:+B>
32
+ # Commits a move and returns a new game state.
61
33
  #
62
- # @example Applying a drop
63
- # qi = Qi.new(true, ['P', 'B', 'G'], ['G', '+B'], {56 => 'P', 64 => '+B'})
64
- # qi.commit(nil, 47, 'G', 'G') #=> <Qi South-turn===B,P,+B,G===47:G,56:P,64:+B>
65
- #
66
- # @return [Qi] the new game state after the move
67
- def commit(src_square, dst_square, piece_name, in_hand, **options)
68
- raise ::ArgumentError, "Both src_square and in_hand cannot be nil" if src_square.nil? && in_hand.nil?
69
-
70
- modified_captures = update_captures(src_square, in_hand)
71
- modified_squares = squares.merge({ src_square => nil, dst_square => piece_name })
72
- self.class.new(south_turn?, *modified_captures, modified_squares, **options)
34
+ # @param capture [String, nil] the piece to be captured.
35
+ # @param drop [String, nil] the piece to be dropped.
36
+ # @param is_in_check [Boolean] whether the current player is in check.
37
+ # @param diffs [Hash] the differences in the state of the board.
38
+ # @return [Qi] the new game state.
39
+ def commit(capture: nil, drop: nil, is_in_check: false, **diffs)
40
+ self.class.new(capture, *captures, drop:, is_in_check:, is_north_turn: south_turn?, **squares.merge(diffs))
73
41
  end
74
42
 
75
- # Compare this Qi object with another for equality.
76
- #
77
- # @example Comparing two Qi objects
78
- # qi1 = Qi.new(...)
79
- # qi2 = Qi.new(...)
80
- # qi1.eql?(qi2) #=> true or false
81
- #
82
- # @param [Qi] other the other Qi object to compare with
83
- # @return [Boolean] true if the two objects represent the same game state, false otherwise
84
- def eql?(other)
85
- return false unless other.respond_to?(:serialize)
86
-
87
- other.serialize == serialize
88
- end
89
- alias == eql?
90
-
91
- # Get the captures of the current player.
92
- #
93
- # The method returns the north player's captures when it's their turn,
94
- # and the south player's captures when it's their turn.
95
- #
96
- # @example When it's the north player's turn
97
- # qi = Qi.new(true, ['P', 'B'], ['G', '+B'], {56 => 'P', 64 => '+B'})
98
- # qi.current_captures #=> ['B', 'P']
99
- #
100
- # @example When it's the south player's turn
101
- # qi = Qi.new(false, ['P', 'B'], ['G', '+B'], {56 => 'P', 64 => '+B'})
102
- # qi.current_captures #=> ['+B', 'G']
103
- #
104
- # @return [Array] the captures of the current player
105
- def current_captures
106
- north_turn? ? north_captures : south_captures
107
- end
108
-
109
- # Get the captures of the opponent player.
110
- #
111
- # @return [Array] the captures of the opponent player
112
- def opponent_captures
113
- north_turn? ? south_captures : north_captures
114
- end
115
-
116
- # Get the current turn.
117
- #
118
- # @return [Symbol] :North if it's the north player's turn, :South otherwise
119
- def current_turn
120
- north_turn? ? North : South
43
+ # @return [Boolean] whether the current player is in check.
44
+ def in_check?
45
+ @is_in_check
121
46
  end
122
47
 
123
- # Get the next turn.
124
- #
125
- # @return [Symbol] :South if it's the north player's turn, :North otherwise
126
- def next_turn
127
- north_turn? ? South : North
48
+ # @return [Boolean] whether the current player is not in check.
49
+ def not_in_check?
50
+ !in_check?
128
51
  end
129
52
 
130
- # Check if it's the north player's turn.
131
- #
132
- # @return [Boolean] true if it's the north player's turn, false otherwise
53
+ # @return [Boolean] whether it's North's turn.
133
54
  def north_turn?
134
55
  @is_north_turn
135
56
  end
136
57
 
137
- # Check if it's the south player's turn.
138
- #
139
- # @return [Boolean] true if it's the south player's turn, false otherwise
58
+ # @return [Boolean] whether it's South's turn.
140
59
  def south_turn?
141
60
  !north_turn?
142
61
  end
143
62
 
144
- # Convert the state to an array.
145
- #
146
- # @example Converting the state to an array
147
- # qi.to_a #=> [true, ['P', 'G'], ['B', '+B'], {56 => 'P', 3 => 'g', 64 => '+B'}, {}]
148
- #
149
- # @return [Array] an array representing the game state
63
+ # @return [Boolean] whether the other game state is equal to this one.
64
+ def eql?(other)
65
+ return false unless other.respond_to?(:serialize)
66
+
67
+ other.serialize == serialize
68
+ end
69
+ alias == eql?
70
+
71
+ # @return [Array] the array representation of the game state.
150
72
  def to_a
151
73
  [
152
74
  north_turn?,
153
- north_captures,
154
- south_captures,
75
+ captures,
155
76
  squares,
156
- options
77
+ in_check?
157
78
  ]
158
79
  end
159
80
 
160
- # Convert the state to a hash.
161
- #
162
- # @example Converting the state to a hash
163
- # qi.to_h #=> {is_north_turn: true, north_captures: ['P', 'G'], south_captures: ['B', '+B'], squares: {56 => 'P', 3 => 'g', 64 => '+B'}, options: {}}
164
- #
165
- # @return [Hash] a hash representing the game state
81
+ # @return [Hash] the hash representation of the game state.
166
82
  def to_h
167
83
  {
168
- is_north_turn: north_turn?,
169
- north_captures:,
170
- south_captures:,
84
+ is_north_turn: north_turn?,
85
+ captures:,
171
86
  squares:,
172
- options:
87
+ is_in_check: in_check?
173
88
  }
174
89
  end
175
90
 
176
- # Generate a hash value for the game state.
177
- #
178
- # @example Generating a hash value
179
- # qi.hash #=> "10dfb778f6559dd368c510a27e3b00bdb5b4ad88d4d67f38864d7e36de7c2f9c"
180
- #
181
- # @return [String] a SHA256 hash of the serialized game state
91
+ # @return [String] the SHA-256 hash of the serialized game state.
182
92
  def hash
183
93
  ::Digest::SHA256.hexdigest(serialize)
184
94
  end
185
95
 
186
- # Serialize the game state.
187
- #
188
- # @example Serializing the game state
189
- # qi.serialize #=> "North-turn===P,G,B,+B===3:g,56:P,64:+B"
190
- #
191
- # @return [String] a string representation of the game state
96
+ # @return [String] the string representation of the game state.
192
97
  def serialize
193
- serialized_turn = "#{current_turn}-turn"
194
- serialized_captures = (north_captures + south_captures).join(",")
195
- serialized_squares = squares.keys.sort.map { |i| "#{i}:#{squares.fetch(i)}" }.join(",")
196
-
197
- "#{serialized_turn}===#{serialized_captures}===#{serialized_squares}"
98
+ [
99
+ serialized_turn,
100
+ serialized_captures,
101
+ serialized_squares,
102
+ serialized_in_check
103
+ ].join(" ")
198
104
  end
199
105
 
200
- # Provide a string representation of the game state for debugging.
201
- #
202
- # @example Getting a string representation of the game state
203
- # qi.inspect #=> "<Qi North-turn===P,G,B,+B===3:g,56:P,64:+B>"
204
- #
205
- # @return [String] a string representation of the game state
106
+ # @return [String] the string representation of the object.
206
107
  def inspect
207
108
  "<#{self.class} #{serialize}>"
208
109
  end
209
110
 
210
111
  private
211
112
 
212
- # Update captures based on the source square and the piece in hand.
213
- #
214
- # If the source square is not nil and in_hand is nil (i.e., we're moving a piece on the board),
215
- # the captures remain the same. If the source square is not nil and in_hand is not nil
216
- # (i.e., we're capturing a piece that will remain in hand), the piece is added to the
217
- # current player's captures. If the source square is nil (i.e., we're dropping a piece from hand),
218
- # the piece is removed from the current player's captures.
219
- #
220
- # @param src_square [Object, nil] the source square, or nil if dropping a piece from hand
221
- # @param in_hand [String, nil] the piece in hand, or nil if moving a piece from a square
222
- #
223
- # @example When moving a piece on the board
224
- # qi = Qi.new(true, ['P', 'B'], ['G', '+B'], {56 => 'P', 64 => '+B'})
225
- # qi.send(:update_captures, 56, nil) #=> [['B', 'P'], ['G', '+B']]
226
- #
227
- # @example When capturing a piece that will remain in hand
228
- # qi = Qi.new(true, ['P', 'B'], ['G', '+B'], {56 => 'P', 64 => '+B'})
229
- # qi.send(:update_captures, 56, 'G') #=> [['B', 'P', 'G'], ['G', '+B']]
230
- #
231
- # @example When dropping a piece from hand
232
- # qi = Qi.new(true, ['P', 'B', 'G'], ['G', '+B'], {56 => 'P', 64 => '+B'})
233
- # qi.send(:update_captures, nil, 'G') #=> [['B', 'P'], ['G', '+B']]
234
- #
235
- # @return [Array] a two-element array with the updated north and south captures
236
- def update_captures(src_square, in_hand)
237
- return [north_captures, south_captures] if in_hand.nil?
238
-
239
- captures = if src_square.nil?
240
- remove_from_captures(in_hand, *current_captures)
241
- else
242
- current_captures + [in_hand]
243
- end
113
+ # @return [String] the serialized turn.
114
+ def serialized_turn
115
+ north_turn? ? "}" : "{"
116
+ end
244
117
 
245
- north_turn? ? [captures, opponent_captures] : [opponent_captures, captures]
118
+ # @return [String] the serialized captures.
119
+ def serialized_captures
120
+ captures.join(";")
246
121
  end
247
122
 
248
- # Removes a piece from the captures.
249
- #
250
- # If the piece is not found in the captures, an Error::Drop exception is raised.
251
- #
252
- # @param piece [String] the piece to remove from the captures
253
- # @param captures [Array] the captures to update
254
- #
255
- # @example
256
- # qi = Qi.new(true, ['P', 'B', 'G'], ['G', '+B'], {56 => 'P', 64 => '+B'})
257
- # qi.send(:remove_from_captures, 'G', *qi.current_captures) #=> ['P', 'B']
258
- #
259
- # @raise [Error::Drop] if the piece is not found in the captures
260
- #
261
- # @return [Array] the captures after removing the piece
262
- def remove_from_captures(piece, *captures)
263
- index = captures.rindex(piece)
264
- raise Error::Drop, "There are no #{piece} in hand" if index.nil?
123
+ # @return [String] the serialized board state.
124
+ def serialized_squares
125
+ squares.keys.sort.map { |i| "#{squares.fetch(i)}@#{i}" }.join(";")
126
+ end
265
127
 
266
- captures.delete_at(index)
267
- captures
128
+ # @return [String] the serialized check state.
129
+ def serialized_in_check
130
+ in_check? ? "+" : "."
268
131
  end
269
132
  end
metadata CHANGED
@@ -1,16 +1,31 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: qi
3
3
  version: !ruby/object:Gem::Version
4
- version: 10.0.0.beta11
4
+ version: 10.0.0.beta12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cyril Kato
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-05-12 00:00:00.000000000 Z
12
- dependencies: []
13
- description: An abstraction that could help to update positions for games like Shogi.
11
+ date: 2023-05-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: kernel-boolean
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ description: A flexible and customizable library for representing and manipulating
28
+ game states, ideal for developing board games like chess, shogi, or xiangqi.
14
29
  email: contact@cyril.email
15
30
  executables: []
16
31
  extensions: []
@@ -19,7 +34,6 @@ files:
19
34
  - LICENSE.md
20
35
  - README.md
21
36
  - lib/qi.rb
22
- - lib/qi/error/drop.rb
23
37
  homepage: https://github.com/sashite/qi.rb
24
38
  licenses:
25
39
  - MIT
@@ -43,5 +57,5 @@ requirements: []
43
57
  rubygems_version: 3.4.10
44
58
  signing_key:
45
59
  specification_version: 4
46
- summary: An abstraction that could help to update positions for games like Shogi.
60
+ summary: Versatile Board Game Position Representation
47
61
  test_files: []
data/lib/qi/error/drop.rb DELETED
@@ -1,13 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class Qi
4
- # The Error module contains custom error classes for the Qi game.
5
- module Error
6
- # The Drop class is a custom error class that inherits from IndexError.
7
- # It is raised when a drop operation in the game of Qi is invalid.
8
- #
9
- # @see IndexError
10
- class Drop < ::IndexError
11
- end
12
- end
13
- end