qi 10.0.0.beta10 → 10.0.0.beta11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +9 -11
  3. data/lib/qi.rb +155 -149
  4. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a009476d5905ba232aed52cafd6f8331632167af3a56c331be1d057b4a1ec964
4
- data.tar.gz: f9a652c101b851e7e07d3b5fd69df6cb1965351697163e73c9600ff4b05251f4
3
+ metadata.gz: 79ffab5e654d14cf9f3f7dac1c50bc5b5c612452d0fdea35a00d3529337fbff2
4
+ data.tar.gz: b8fecf9ff5dd97923070809b6a906c8b44cebbee9695ea242e314d53afb9fad8
5
5
  SHA512:
6
- metadata.gz: 31c3aa57ebd829dcf24ca9604ef9a17dfb6a44fd0fd727dae76a730d3908c2f8cd2ba17d6dbc037ca9de88ac5913b4b4e759a967426d3e0c39b2100abb4891b1
7
- data.tar.gz: 7b95a0bfdddd2be4fcdda01b64b2e42fc120f84d8becc5a5561383a41d88394a8d3a4e7b58a6d0721505d316c5e6e1357a0ddfff28f4179dec25c6af8e4b7688
6
+ metadata.gz: cb36bd477ba3e756b116e3f2ab55bdb15ea50834461cc614865d8fdda56e271eff4675d998172bd766b8ca33e6944be3bbf567a1eba96b6215816234c485f6c9
7
+ data.tar.gz: e56b5f73bf2c0a1a3a256f813acfcf24af3bc3cdd570f2fb6ab1aa2f7ebc194ddd0b82e5ade5cbc052229377a8c768d3f49f45188d811a756ab7781481c69f08
data/README.md CHANGED
@@ -13,7 +13,7 @@
13
13
  Add this line to your application's Gemfile:
14
14
 
15
15
  ```ruby
16
- gem "qi", ">= 10.0.0.beta10"
16
+ gem "qi", ">= 10.0.0.beta11"
17
17
  ```
18
18
 
19
19
  And then execute:
@@ -38,39 +38,37 @@ 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
38
  south_captures = %w[S]
39
39
  squares = { 3 => "s", 4 => "k", 5 => "s", 22 => "+P", 43 => "+B" }
40
40
 
41
- qi0 = Qi.new(is_north_turn, north_captures, south_captures, squares, false)
41
+ qi0 = Qi.new(is_north_turn, north_captures, south_captures, squares)
42
42
 
43
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
44
  qi0.south_captures # => ["S"]
45
45
  qi0.squares # => {3=>"s", 4=>"k", 5=>"s", 22=>"+P", 43=>"+B"}
46
46
  qi0.north_turn? # => false
47
47
  qi0.south_turn? # => true
48
- qi0.serialize # => "South-turn===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===3:s,4:k,5:s,22:+P,43:+B===not-in-check"
49
- qi0.inspect # => "<Qi South-turn===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===3:s,4:k,5:s,22:+P,43:+B===not-in-check>"
50
-
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>"
51
50
  qi0.to_a
52
51
  # [false,
53
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"],
54
53
  # ["S"],
55
54
  # {3=>"s", 4=>"k", 5=>"s", 22=>"+P", 43=>"+B"},
56
- # false]
55
+ # {}]
57
56
 
58
- qi1 = qi0.commit({ 43 => nil, 13 => "+B" }, nil, is_drop: nil, is_in_check: true)
57
+ qi1 = qi0.commit(43, 13, "+B", nil)
59
58
 
60
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"]
61
60
  qi1.south_captures # => ["S"]
62
61
  qi1.squares # => {3=>"s", 4=>"k", 5=>"s", 22=>"+P", 13=>"+B"}
63
62
  qi1.north_turn? # => true
64
63
  qi1.south_turn? # => false
65
- qi1.serialize # => "North-turn===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===3:s,4:k,5:s,22:+P,13:+B===in-check"
66
- qi1.inspect # => "<Qi North-turn===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===3:s,4:k,5:s,22:+P,13:+B===in-check>"
67
-
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>"
68
66
  qi1.to_a
69
67
  # [true,
70
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"],
71
69
  # ["S"],
72
70
  # {3=>"s", 4=>"k", 5=>"s", 22=>"+P", 13=>"+B"},
73
- # true]
71
+ # {}]
74
72
  ```
75
73
 
76
74
  ## License
data/lib/qi.rb CHANGED
@@ -3,69 +3,84 @@
3
3
  require "digest"
4
4
  require_relative "qi/error/drop"
5
5
 
6
- # The Qi class represents the current state of a game, tracking both the positions of pieces on the board and the pieces captured by each player.
7
- # It provides methods for manipulating the game state, including moving pieces around the board, capturing opponent's pieces, and dropping pieces from hand onto the board.
8
- # Additionally, it maintains information about the current game turn (which player's turn it is) and whether a player is in check.
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.
9
8
  class Qi
10
- # Constant representing the North player.
11
- North = "North"
9
+ # Constants for representing the North and South players.
10
+ North = :North
11
+ South = :South
12
12
 
13
- # Constant representing the South player.
14
- South = "South"
15
-
16
- # @!attribute [r] north_captures
17
- # @return [Array] The list of pieces captured by the North player.
13
+ # @return [Array] the pieces captured by the north player
18
14
  attr_reader :north_captures
19
15
 
20
- # @!attribute [r] south_captures
21
- # @return [Array] The list of pieces captured by the South player.
16
+ # @return [Array] the pieces captured by the south player
22
17
  attr_reader :south_captures
23
18
 
24
- # @!attribute [r] squares
25
- # @return [Hash] The current state of the board, represented as a hash where each key is a position and each value is the state of that position.
19
+ # @return [Hash] the current state of the game board
26
20
  attr_reader :squares
27
21
 
28
- # Initializes a new instance of the game state.
29
- #
30
- # @param is_north_turn [Boolean] True if it's North's turn, false otherwise.
31
- # @param north_captures [Array] An array representing the pieces captured by North.
32
- # @param south_captures [Array] An array representing the pieces captured by South.
33
- # @param squares [Hash] A hash representing the state of the squares on the board.
34
- # @param is_in_check [Boolean] True if the current player is in check, false otherwise.
35
- def initialize(is_north_turn, north_captures, south_captures, squares, is_in_check)
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
36
  @is_north_turn = is_north_turn
37
37
  @north_captures = north_captures.sort
38
38
  @south_captures = south_captures.sort
39
39
  @squares = squares.compact
40
- @is_in_check = is_in_check
40
+ @options = options
41
41
  end
42
42
 
43
- # Creates a new game state by applying a set of diffs to the squares and the captures.
44
- # Raises an error if in_hand is provided but is_drop is not, or vice versa.
45
- #
46
- # @param diffs [Hash] A hash representing the changes to the squares. Each key is a position, and each value is the new state of that position.
47
- # @param in_hand [String, nil] A string representing the piece that the current player has in hand, or nil if no piece is in hand.
48
- # @param is_drop [Boolean, nil] True if the current player is dropping a piece, false if they are not, or nil if there is no piece in hand.
49
- # @param is_in_check [Boolean] True if the current player is in check after the move, false otherwise.
50
- # @return [Qi] The new game state after applying the diffs.
51
- # @raise [ArgumentError] If in_hand is provided but is_drop is not, or vice versa.
52
- def commit(diffs, in_hand, is_drop:, is_in_check:)
53
- if !in_hand.nil? && is_drop.nil?
54
- raise ::ArgumentError, "A piece is in hand, but is_drop is not provided"
55
- elsif in_hand.nil? && !is_drop.nil?
56
- raise ::ArgumentError, "No piece is in hand, but is_drop is provided"
57
- end
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>
61
+ #
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?
58
69
 
59
- modified_squares = squares.merge(diffs)
60
- modified_captures = update_captures(in_hand, is_drop:)
61
- self.class.new(south_turn?, *modified_captures, modified_squares, is_in_check)
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)
62
73
  end
63
74
 
64
- # Checks if this game state is equal to another.
65
- # Two game states are considered equal if they can be serialized to the same string.
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
66
81
  #
67
- # @param other [Object] The object to compare with this game state.
68
- # @return [Boolean] True if the other object can be serialized and its serialized form is equal to this game state's serialized form, false otherwise.
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
69
84
  def eql?(other)
70
85
  return false unless other.respond_to?(:serialize)
71
86
 
@@ -73,171 +88,155 @@ class Qi
73
88
  end
74
89
  alias == eql?
75
90
 
76
- # Returns the captures of the current player.
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']
77
103
  #
78
- # @return [Array] An array or other iterable representing the pieces captured by the current player.
104
+ # @return [Array] the captures of the current player
79
105
  def current_captures
80
- if north_turn?
81
- north_captures
82
- else
83
- south_captures
84
- end
106
+ north_turn? ? north_captures : south_captures
85
107
  end
86
108
 
87
- # Returns the list of pieces that the current player's opponent has captured.
109
+ # Get the captures of the opponent player.
88
110
  #
89
- # @return [Array] An array of pieces that the opponent has captured.
111
+ # @return [Array] the captures of the opponent player
90
112
  def opponent_captures
91
- if north_turn?
92
- south_captures
93
- else
94
- north_captures
95
- end
113
+ north_turn? ? south_captures : north_captures
96
114
  end
97
115
 
98
- # Returns the name of the current side.
116
+ # Get the current turn.
99
117
  #
100
- # @return [String] "North" if it's North's turn, "South" otherwise.
118
+ # @return [Symbol] :North if it's the north player's turn, :South otherwise
101
119
  def current_turn
102
- if north_turn?
103
- North
104
- else
105
- South
106
- end
120
+ north_turn? ? North : South
107
121
  end
108
122
 
109
- # Returns the name of the next side.
110
- # If it's currently the North player's turn, this method will return "South", and vice versa.
123
+ # Get the next turn.
111
124
  #
112
- # @return [String] "South" if it's North's turn, "North" otherwise.
125
+ # @return [Symbol] :South if it's the north player's turn, :North otherwise
113
126
  def next_turn
114
- if north_turn?
115
- South
116
- else
117
- North
118
- end
127
+ north_turn? ? South : North
119
128
  end
120
129
 
121
- # Checks if it's North's turn.
130
+ # Check if it's the north player's turn.
122
131
  #
123
- # @return [Boolean] True if it's North's turn, false otherwise.
132
+ # @return [Boolean] true if it's the north player's turn, false otherwise
124
133
  def north_turn?
125
134
  @is_north_turn
126
135
  end
127
136
 
128
- # Checks if it's South's turn.
137
+ # Check if it's the south player's turn.
129
138
  #
130
- # @return [Boolean] True if it's South's turn, false otherwise.
139
+ # @return [Boolean] true if it's the south player's turn, false otherwise
131
140
  def south_turn?
132
141
  !north_turn?
133
142
  end
134
143
 
135
- # Checks if the current player is in check.
144
+ # Convert the state to an array.
136
145
  #
137
- # @return [Boolean] True if the current player is in check, false otherwise.
138
- def in_check?
139
- @is_in_check
140
- end
141
-
142
- # Checks if the current player is not in check.
146
+ # @example Converting the state to an array
147
+ # qi.to_a #=> [true, ['P', 'G'], ['B', '+B'], {56 => 'P', 3 => 'g', 64 => '+B'}, {}]
143
148
  #
144
- # @return [Boolean] True if the current player is not in check, false otherwise.
145
- def not_in_check?
146
- !in_check?
147
- end
148
-
149
- # Converts the current game state to an array. The resulting array includes:
150
- # whether it's North's turn, the pieces captured by North, the pieces captured by South,
151
- # the state of the squares, and whether the current player is in check.
152
- # This array can be used for various purposes, such as saving the game state,
153
- # transmitting the game state over a network, or analyzing the game state.
154
- #
155
- # @return [Array] The game state, represented as an array. The elements of the array are:
156
- # - A boolean indicating whether it's North's turn,
157
- # - An array or other iterable representing the pieces captured by North,
158
- # - An array or other iterable representing the pieces captured by South,
159
- # - A data structure representing the state of the squares on the board,
160
- # - A boolean indicating whether the current player is in check.
149
+ # @return [Array] an array representing the game state
161
150
  def to_a
162
151
  [
163
152
  north_turn?,
164
153
  north_captures,
165
154
  south_captures,
166
155
  squares,
167
- in_check?
156
+ options
168
157
  ]
169
158
  end
170
159
 
171
- # Converts the current game state to a hash. The resulting hash includes:
172
- # whether it's North's turn, the pieces captured by North, the pieces captured by South,
173
- # the state of the squares, and whether the current player is in check.
174
- # This hash can be used for various purposes, such as saving the game state,
175
- # transmitting the game state over a network, or analyzing the game state.
176
- #
177
- # @return [Hash] The game state, represented as a hash. The keys of the hash are:
178
- # - :is_north_turn, a boolean indicating whether it's North's turn,
179
- # - :north_captures, an array or other iterable representing the pieces captured by North,
180
- # - :south_captures, an array or other iterable representing the pieces captured by South,
181
- # - :squares, a data structure representing the state of the squares on the board,
182
- # - :is_in_check, a boolean indicating whether the current player is in check.
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
183
166
  def to_h
184
167
  {
185
168
  is_north_turn: north_turn?,
186
169
  north_captures:,
187
170
  south_captures:,
188
171
  squares:,
189
- is_in_check: in_check?
172
+ options:
190
173
  }
191
174
  end
192
175
 
193
- # Returns the hash-code for the position.
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
194
182
  def hash
195
183
  ::Digest::SHA256.hexdigest(serialize)
196
184
  end
197
185
 
198
- # Returns a sorted list of all pieces currently on the board.
186
+ # Serialize the game state.
199
187
  #
200
- # @return [Array] An array of all pieces currently on the board.
201
- def board_pieces
202
- squares.keys.sort
203
- end
204
-
205
- # Serialize the current game state to a string. The serialized state includes:
206
- # the current turn, the captured pieces, the state of the squares, and whether
207
- # the current player is in check. The serialized state can be used to save
208
- # the game, or to transmit the game state over a network.
188
+ # @example Serializing the game state
189
+ # qi.serialize #=> "North-turn===P,G,B,+B===3:g,56:P,64:+B"
209
190
  #
210
- # @return [String] The serialized game state.
191
+ # @return [String] a string representation of the game state
211
192
  def serialize
212
193
  serialized_turn = "#{current_turn}-turn"
213
- serialized_captures = (north_captures + south_captures).sort.join(",")
214
- serialized_squares = board_pieces.map { |i| "#{i}:#{squares.fetch(i)}" }.join(",")
215
- serialized_check = (in_check? ? "in-check" : "not-in-check")
194
+ serialized_captures = (north_captures + south_captures).join(",")
195
+ serialized_squares = squares.keys.sort.map { |i| "#{i}:#{squares.fetch(i)}" }.join(",")
216
196
 
217
- "#{serialized_turn}===#{serialized_captures}===#{serialized_squares}===#{serialized_check}"
197
+ "#{serialized_turn}===#{serialized_captures}===#{serialized_squares}"
218
198
  end
219
199
 
220
- # Provides a string representation of the game state, including the class name and the serialized game state.
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>"
221
204
  #
222
- # @return [String] A string representation of the game state.
205
+ # @return [String] a string representation of the game state
223
206
  def inspect
224
207
  "<#{self.class} #{serialize}>"
225
208
  end
226
209
 
227
210
  private
228
211
 
229
- # Updates the list of captures based on the piece in hand and whether the move is a drop.
230
- # If the in_hand parameter is nil, the method returns the current captures without modification.
231
- # Otherwise, the method either adds the piece in hand to the current player's captures (if is_drop is false),
232
- # or removes the piece in hand from the current player's captures (if is_drop is true).
233
- #
234
- # @param in_hand [String, nil] The piece in hand, or nil if no piece is in hand.
235
- # @param is_drop [Boolean] True if the current move is a drop, false otherwise.
236
- # @return [Array] The updated list of captures for North and South.
237
- def update_captures(in_hand, is_drop:)
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)
238
237
  return [north_captures, south_captures] if in_hand.nil?
239
238
 
240
- captures = if is_drop
239
+ captures = if src_square.nil?
241
240
  remove_from_captures(in_hand, *current_captures)
242
241
  else
243
242
  current_captures + [in_hand]
@@ -247,12 +246,19 @@ class Qi
247
246
  end
248
247
 
249
248
  # Removes a piece from the captures.
250
- # The method raises an error if the piece is not found in the captures.
251
249
  #
252
- # @param piece [String] The piece to remove from the captures.
253
- # @param captures [Array] The list of captures.
254
- # @return [Array] The updated list of captures.
255
- # @raise [Error::Drop] If the piece is not found in the captures.
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
256
262
  def remove_from_captures(piece, *captures)
257
263
  index = captures.rindex(piece)
258
264
  raise Error::Drop, "There are no #{piece} in hand" if index.nil?
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: qi
3
3
  version: !ruby/object:Gem::Version
4
- version: 10.0.0.beta10
4
+ version: 10.0.0.beta11
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-11 00:00:00.000000000 Z
11
+ date: 2023-05-12 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: An abstraction that could help to update positions for games like Shogi.
14
14
  email: contact@cyril.email