qi 10.0.0.beta4 → 10.0.0.beta5

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 (6) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +63 -8
  3. data/lib/qi.rb +122 -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: 73eb059b5776d83c165ffe3a37592221e2c28a449cc271b74be2644c9e8e1ed3
4
+ data.tar.gz: 37f4b7fe311e4ed0ce178031b17dd45e19281a9778b16785a0e829580c52d93b
5
5
  SHA512:
6
- metadata.gz: 00aa0f50dd054bc1c15a0de068b4c7e2e3e18d2fc63da9db8c781f72058efc472409fe474545a6b088cb9a5b62ad87120baebbb3ad24e3cada79d6a3726f02c6
7
- data.tar.gz: d6909071d69cd7308e2655a5331b1d522e424cf05b002a73da5a54e4c7f570533d44c7db23111f4b609d876bf415b742127e0613b38685a49ccc465638c57427
6
+ metadata.gz: c9feb0ac434f46f4b1d0c6c201ae0d64c084bc4b5b76b82eff8002eb1109580f018d2df65906a0c098129a28d1a2da06744252bcbb04ef1934b926c50ec4cd89
7
+ data.tar.gz: 89cbfe6706285b7f482161c2b7188afcc6b94c69aa002bb9f42218b7d246c2066876dc73506a83fcd63ea84430302c4f92feda6f4685749ef9200dba9f8ad2cf
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,68 @@ 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.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>"
49
+
50
+ qi0.to_a
51
+ # [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"],
54
+ # {3=>"s", 4=>"k", 5=>"s", 22=>"+P", 43=>"+B"}]
55
+
56
+ qi0.display(81, 9)
57
+ # [["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"],
58
+ # [[". ", ". ", ". ", "s ", "k ", "s ", ". ", ". ", ". "],
59
+ # [". ", ". ", ". ", ". ", ". ", ". ", ". ", ". ", ". "],
60
+ # [". ", ". ", ". ", ". ", "+P", ". ", ". ", ". ", ". "],
61
+ # [". ", ". ", ". ", ". ", ". ", ". ", ". ", ". ", ". "],
62
+ # [". ", ". ", ". ", ". ", ". ", ". ", ". ", "+B", ". "],
63
+ # [". ", ". ", ". ", ". ", ". ", ". ", ". ", ". ", ". "],
64
+ # [". ", ". ", ". ", ". ", ". ", ". ", ". ", ". ", ". "],
65
+ # [". ", ". ", ". ", ". ", ". ", ". ", ". ", ". ", ". "],
66
+ # [". ", ". ", ". ", ". ", ". ", ". ", ". ", ". ", ". "]],
67
+ # ["S"],
68
+ # "Turn to south"]
69
+
70
+ qi1 = qi0.commit({ 43 => nil, 13 => "+B" })
71
+
72
+ 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"]
73
+ qi1.south_captures # => ["S"]
74
+ qi1.squares # => {3=>"s", 4=>"k", 5=>"s", 22=>"+P", 13=>"+B"}
75
+ qi1.north_turn? # => true
76
+ qi1.south_turn? # => false
77
+ 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>"
78
+
79
+ qi1.to_a
80
+ # [true,
81
+ # ["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"],
82
+ # ["S"],
83
+ # {3=>"s", 4=>"k", 5=>"s", 22=>"+P", 13=>"+B"}]
84
+
85
+ qi1.display(81, 9)
86
+ # [["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"],
87
+ # [[". ", ". ", ". ", "s ", "k ", "s ", ". ", ". ", ". "],
88
+ # [". ", ". ", ". ", ". ", "+B", ". ", ". ", ". ", ". "],
89
+ # [". ", ". ", ". ", ". ", "+P", ". ", ". ", ". ", ". "],
90
+ # [". ", ". ", ". ", ". ", ". ", ". ", ". ", ". ", ". "],
91
+ # [". ", ". ", ". ", ". ", ". ", ". ", ". ", ". ", ". "],
92
+ # [". ", ". ", ". ", ". ", ". ", ". ", ". ", ". ", ". "],
93
+ # [". ", ". ", ". ", ". ", ". ", ". ", ". ", ". ", ". "],
94
+ # [". ", ". ", ". ", ". ", ". ", ". ", ". ", ". ", ". "],
95
+ # [". ", ". ", ". ", ". ", ". ", ". ", ". ", ". ", ". "]],
96
+ # ["S"],
97
+ # "Turn to north"]
43
98
  ```
44
99
 
45
100
  ## License
data/lib/qi.rb CHANGED
@@ -1,7 +1,126 @@
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 parameters.
14
+ # @param is_north_turn [Boolean] a boolean value indicating whose turn it is
15
+ # @param north_captures [Array] an array of pieces captured by the north player
16
+ # @param south_captures [Array] an array of pieces captured by the south player
17
+ # @param squares [Hash] a hash of pieces on the board
18
+ def initialize(is_north_turn, north_captures, south_captures, squares)
19
+ # Assign the parameters to instance variables.
20
+ @is_north_turn = is_north_turn
21
+ @north_captures = north_captures.sort
22
+ @south_captures = south_captures.sort
23
+ @squares = squares.compact
24
+ end
25
+
26
+ # Returns a new Qi object that represents the state after applying the given changes.
27
+ # @param diffs [Hash] a hash of changes to apply to the squares hash
28
+ # @param in_hand [Object, nil] the piece that is in hand or nil if none
29
+ # @param is_drop [Boolean] a boolean value indicating whether the in hand piece is dropped or not
30
+ # @return [Qi] a new Qi object with modified attributes
31
+ def commit(diffs = {}, in_hand = nil, is_drop = false)
32
+ modified_squares = squares.merge(diffs)
33
+
34
+ if in_hand.nil?
35
+ self.class.new(south_turn?, north_captures, south_captures, modified_squares)
36
+ elsif north_turn?
37
+ modified_captures = if is_drop
38
+ remove_from_captures(in_hand, *north_captures)
39
+ else
40
+ north_captures + [in_hand]
41
+ end
42
+
43
+ self.class.new(false, modified_captures, south_captures, modified_squares)
44
+ else
45
+ modified_captures = if is_drop
46
+ remove_from_captures(in_hand, *south_captures)
47
+ else
48
+ south_captures + [in_hand]
49
+ end
50
+
51
+ self.class.new(true, north_captures, modified_captures, modified_squares)
52
+ end
53
+ end
54
+
55
+ # Checks if it is the north turn or not.
56
+ # @return [Boolean] true if it is the north turn and false otherwise
57
+ def north_turn?
58
+ @is_north_turn
59
+ end
60
+
61
+ # Checks if it is not the north turn or not.
62
+ # @return [Boolean] true if it is not the north turn and false otherwise
63
+ def south_turn?
64
+ !north_turn?
65
+ end
66
+
67
+ # Returns an array representation of the Qi object's attributes.
68
+ # @return [Array] an array containing four elements:
69
+ # - a boolean value indicating whose turn it is
70
+ # - an array of pieces captured by the north player
71
+ # - an array of pieces captured by the south player
72
+ # - a hash of squares on the board
73
+ def to_a
74
+ [
75
+ north_turn?,
76
+ north_captures,
77
+ south_captures,
78
+ squares
79
+ ]
80
+ end
81
+
82
+ # Returns an array representation of the Qi object's attributes for display purposes.
83
+ # @param size [Integer] the number of squares on the board
84
+ # @param cols [Integer] the number of columns on the board
85
+ # @return [Array] an array containing four elements:
86
+ # - an array of pieces captured by the north player
87
+ # - a nested array of strings representing the squares on the board
88
+ # - an array of pieces captured by the south player
89
+ # - a string indicating whose turn it is
90
+ def display(size, cols)
91
+ square_size = squares.values.max_by(&:length).length
92
+ board = (0...size).to_a.map { |i| squares.fetch(i, ".") }.map { |square| square.center(square_size) }.each_slice(cols).to_a
93
+ turn = (north_turn? ? "Turn to north" : "Turn to south")
94
+
95
+ [
96
+ north_captures,
97
+ board,
98
+ south_captures,
99
+ turn
100
+ ]
101
+ end
102
+
103
+ # Returns a string representation of the Qi object's attributes.
104
+ # @return [String] a string containing the turn, the captures and the squares in a formatted way.
105
+ def inspect
106
+ serialized_turn = (north_turn? ? "north-turn" : "south-turn")
107
+ serialized_captures = captures.join(",")
108
+ serialized_squares = squares.keys.map { |i| "#{i}:#{squares.fetch(i)}" }.join(",")
109
+
110
+ "<Qi #{serialized_turn} #{serialized_captures} #{serialized_squares}>"
111
+ end
112
+
113
+ private
114
+
115
+ def captures
116
+ south_captures + north_captures
117
+ end
118
+
119
+ def remove_from_captures(captured_piece, *captured_pieces)
120
+ capture_id = captured_pieces.rindex(captured_piece)
121
+ raise ::IndexError, "#{captured_piece} not found!" if capture_id.nil?
122
+
123
+ captured_pieces.delete_at(capture_id)
124
+ captured_pieces
125
+ end
7
126
  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.beta5
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-22 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