qi 10.0.0.beta10 → 10.0.0.beta11

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.
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