qi 10.0.0.beta4 → 10.0.0.beta5

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