qi 10.0.0.beta4 → 10.0.0.beta6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (6) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +37 -8
  3. data/lib/qi.rb +124 -3
  4. metadata +2 -4
  5. data/lib/kernel.rb +0 -18
  6. data/lib/qi/action.rb +0 -34
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ba69668b35781db7bbad0806b6940d99924fa3693355f01538b14bb8ebf159e7
4
- data.tar.gz: 8447f2df3687f661762d1a99adffc31640d693f52a4012adf2f89825b2614239
3
+ metadata.gz: 638a4dafc9645e200d72d7799afb3f28cca3a81f7cd887e5f29c64974e5776e0
4
+ data.tar.gz: 5e74a8a31f894187b404a3c41ed1a1434916880925934f2fe627e19472f99084
5
5
  SHA512:
6
- metadata.gz: 00aa0f50dd054bc1c15a0de068b4c7e2e3e18d2fc63da9db8c781f72058efc472409fe474545a6b088cb9a5b62ad87120baebbb3ad24e3cada79d6a3726f02c6
7
- data.tar.gz: d6909071d69cd7308e2655a5331b1d522e424cf05b002a73da5a54e4c7f570533d44c7db23111f4b609d876bf415b742127e0613b38685a49ccc465638c57427
6
+ metadata.gz: 41a6e8c87db922ca87d992b62909c6cf5d87d8900d12c9bc0b43d94d1882040d168678ee9d3f6be85904b7f275a0eaa9c42e32364b0d7c5e4766ec84953fdb10
7
+ data.tar.gz: 14323df90b7e942fbae1a1db4f3e23f071c4fdd62bd969797a39909c710e599534c5eaa2fd4b6a01ffbe91f48d25122a28c32b599fc5731f9b3c14b72c2f8a74
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.beta3"
16
+ gem "qi", ">= 10.0.0.beta5"
17
17
  ```
18
18
 
19
19
  And then execute:
@@ -33,13 +33,42 @@ gem install qi --pre
33
33
  ```ruby
34
34
  require "qi"
35
35
 
36
- captures = %w[S 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]
37
- squares = { "3": "s", "4": "k", "5": "s", "22": "+P", "43": "+B" }
38
-
39
- captures, squares = Qi(*captures, **squares).call("43": nil, "13": "+B")
40
-
41
- captures # => ["S", "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"]
42
- squares # => {:"3"=>"s", :"4"=>"k", :"5"=>"s", :"22"=>"+P", :"13"=>"+B"}
36
+ is_north_turn = false
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
+ south_captures = %w[S]
39
+ squares = { 3 => "s", 4 => "k", 5 => "s", 22 => "+P", 43 => "+B" }
40
+
41
+ qi0 = Qi.new(is_north_turn, north_captures, south_captures, squares)
42
+
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 # => "SouthTurn===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"
49
+ qi0.inspect # => "<Qi SouthTurn===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>"
50
+
51
+ qi0.to_a
52
+ # [false,
53
+ # ["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
+ # ["S"],
55
+ # {3=>"s", 4=>"k", 5=>"s", 22=>"+P", 43=>"+B"}]
56
+
57
+ qi1 = qi0.commit({ 43 => nil, 13 => "+B" })
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 # => "NorthTurn===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"
65
+ qi1.inspect # => "<Qi NorthTurn===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>"
66
+
67
+ qi1.to_a
68
+ # [true,
69
+ # ["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
+ # ["S"],
71
+ # {3=>"s", 4=>"k", 5=>"s", 22=>"+P", 13=>"+B"}]
43
72
  ```
44
73
 
45
74
  ## License
data/lib/qi.rb CHANGED
@@ -1,7 +1,128 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "kernel"
3
+ # A class that represents the state of a game.
4
+ class Qi
5
+ # @!attribute [r] north_captures
6
+ # @return [Array] an array of pieces captured by the north player
7
+ # @!attribute [r] south_captures
8
+ # @return [Array] an array of pieces captured by the south player
9
+ # @!attribute [r] squares
10
+ # @return [Hash] a hash of pieces on the board
11
+ attr_reader :north_captures, :south_captures, :squares
4
12
 
5
- # The Qi abstraction.
6
- module Qi
13
+ # Initializes a new Qi object with the given attributes.
14
+ #
15
+ # @param is_north_turn [Boolean] a boolean value indicating whose turn it is
16
+ # @param north_captures [Array<Object>] an array of pieces captured by the north player
17
+ # @param south_captures [Array<Object>] an array of pieces captured by the south player
18
+ # @param squares [Hash<Object, Object>] a hash of squares on the board
19
+ def initialize(is_north_turn, north_captures, south_captures, squares)
20
+ # Assign the parameters to instance variables.
21
+ @is_north_turn = is_north_turn
22
+ @north_captures = north_captures.sort
23
+ @south_captures = south_captures.sort
24
+ @squares = squares.compact
25
+ end
26
+
27
+ # Returns a new Qi object that represents the state after applying the given changes.
28
+ #
29
+ # @param diffs [Hash<Object, Object>] a hash of changes to apply to the squares hash
30
+ # @param in_hand [Object, nil] the piece that is in hand or nil if none
31
+ # @param is_drop [Boolean] a boolean value indicating whether the in hand piece is dropped or not
32
+ # @return [Qi] a new Qi object with modified attributes, where:
33
+ # - the turn is switched
34
+ # - the captures are updated according to the in hand piece and the drop flag
35
+ # - the squares are merged with the diffs hash
36
+ def commit(diffs = {}, in_hand = nil, is_drop: false)
37
+ modified_squares = squares.merge(diffs)
38
+ modified_captures = update_captures(in_hand, is_drop:)
39
+ self.class.new(!north_turn?, *modified_captures, modified_squares)
40
+ end
41
+
42
+ # Checks if it is the north turn or not.
43
+ #
44
+ # @return [Boolean] true if it is the north turn and false otherwise
45
+ def north_turn?
46
+ @is_north_turn
47
+ end
48
+
49
+ # Checks if it is not the north turn or not.
50
+ #
51
+ # @return [Boolean] true if it is not the north turn and false otherwise
52
+ def south_turn?
53
+ !north_turn?
54
+ end
55
+
56
+ # Returns an array representation of the Qi object's attributes.
57
+ #
58
+ # @return [Array(Boolean, Array<Object>, Array<Object>, Hash<Object, Object>)] an array containing four elements:
59
+ # - a boolean value indicating whose turn it is
60
+ # - an array of pieces captured by the north player
61
+ # - an array of pieces captured by the south player
62
+ # - a hash of squares on the board
63
+ def to_a
64
+ [
65
+ north_turn?,
66
+ north_captures,
67
+ south_captures,
68
+ squares
69
+ ]
70
+ end
71
+
72
+ # Returns a string representation of the Qi object's attributes.
73
+ #
74
+ # @return [String] a string containing three parts separated by "===":
75
+ # - the current turn, either "NorthTurn" or "SouthTurn"
76
+ # - the captures, sorted and joined by ","
77
+ # - the squares, mapped to "coordinate:piece" pairs and joined by ","
78
+ def serialize
79
+ serialized_turn = (north_turn? ? "NorthTurn" : "SouthTurn")
80
+ serialized_captures = (north_captures + south_captures).sort.join(",")
81
+ serialized_squares = squares.keys.map { |i| "#{i}:#{squares.fetch(i)}" }.join(",")
82
+
83
+ "#{serialized_turn}===#{serialized_captures}===#{serialized_squares}"
84
+ end
85
+
86
+ # Returns a human-readable representation of the Qi object.
87
+ #
88
+ # @return [String] a string containing the class name and the serialized attributes
89
+ def inspect
90
+ "<#{self.class} #{serialize}>"
91
+ end
92
+
93
+ private
94
+
95
+ # Updates the captures arrays based on the piece in hand and whether it is dropped or not.
96
+ #
97
+ # @param in_hand [Object, nil] the piece that is in hand or nil if none
98
+ # @param is_drop [Boolean] a boolean value indicating whether the in hand piece is dropped or not
99
+ # @return [Array] an array containing the updated north and south captures arrays
100
+ def update_captures(in_hand, is_drop:)
101
+ return [north_captures, south_captures] if in_hand.nil?
102
+
103
+ captures = north_turn? ? north_captures : south_captures
104
+ other_captures = north_turn? ? south_captures : north_captures
105
+
106
+ if is_drop
107
+ captures = remove_from_captures(in_hand, *captures)
108
+ else
109
+ captures += [in_hand]
110
+ end
111
+
112
+ north_turn? ? [captures, other_captures] : [other_captures, captures]
113
+ end
114
+
115
+ # Removes the last occurrence of a piece from an array of captures and returns the modified array.
116
+ #
117
+ # @param piece [Object] the piece to be removed
118
+ # @param captures [Array<Object>] the array of captures
119
+ # @return [Array<Object>] the modified array of captures
120
+ # @raise [IndexError] if the piece is not found in the array
121
+ def remove_from_captures(piece, *captures)
122
+ index = captures.rindex(piece)
123
+ raise ::IndexError, "#{piece} not found!" if index.nil?
124
+
125
+ captures.delete_at(index)
126
+ captures
127
+ end
7
128
  end
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.beta4
4
+ version: 10.0.0.beta6
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-04-21 00:00:00.000000000 Z
11
+ date: 2023-04-23 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
@@ -18,9 +18,7 @@ extra_rdoc_files: []
18
18
  files:
19
19
  - LICENSE.md
20
20
  - README.md
21
- - lib/kernel.rb
22
21
  - lib/qi.rb
23
- - lib/qi/action.rb
24
22
  homepage: https://github.com/sashite/qi.rb
25
23
  licenses:
26
24
  - MIT
data/lib/kernel.rb DELETED
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
- # shareable_constant_value: none
3
-
4
- # warn_indent: true
5
-
6
- require_relative File.join("qi", "action")
7
-
8
- # The Kernel module.
9
- module Kernel
10
- # Abstraction to build positions.
11
- #
12
- # @return [Array] An action to change the position.
13
- #
14
- # @api public
15
- def Qi(*captures, **squares)
16
- ::Qi::Action.new(*captures, **squares)
17
- end
18
- end
data/lib/qi/action.rb DELETED
@@ -1,34 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Qi
4
- # The Action abstraction.
5
- class Action
6
- CAPTURE_CHAR = "&"
7
- DROP_CHAR = "*"
8
-
9
- # Action initializer.
10
- def initialize(*captures, **squares)
11
- @captures = captures
12
- @squares = squares
13
- end
14
-
15
- # Commit an action to the position.
16
- #
17
- # @return [Array] An action to change the position.
18
- def call(**diffs)
19
- captures = @captures + Array(diffs.delete(CAPTURE_CHAR))
20
- drop = diffs.delete(DROP_CHAR)
21
-
22
- unless drop.nil?
23
- index = captures.rindex(drop)
24
- raise ::IndexError, "Piece #{drop.inspect} not captured!" if index.nil?
25
-
26
- captures.delete_at(index)
27
- end
28
-
29
- squares = @squares.merge(diffs).compact
30
-
31
- [captures.sort, squares]
32
- end
33
- end
34
- end