qi 10.0.0.beta10 → 10.0.0.beta12
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +34 -25
- data/lib/qi.rb +70 -201
- metadata +20 -6
- data/lib/qi/error/drop.rb +0 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7f3a609bb51c87ae5486c9244b948899f4e6ae46747ac80bf3be5f83ae76826a
|
4
|
+
data.tar.gz: 1843fa6cc35f2dcaaab08a7772abeb9f56fa3e7d0dc5dc69f9a742ec47e81169
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f79f7dc430f3e84b5cf816492c4f31c7776db329fffd18e161df929ccf18cb85b37cdd69e35c2b93da0e983e976d765bf69e8a33f1e946ec62d61c7b5583d164
|
7
|
+
data.tar.gz: '059b84b8c426af80188f0b6885ff921ab86f7015756d5309d75fd0ab621f1d93322be5f83f603a02535850645da432219af815871c480b56dec0e8f67db738bb'
|
data/README.md
CHANGED
@@ -6,14 +6,25 @@
|
|
6
6
|
[![RuboCop](https://github.com/sashite/qi.rb/workflows/RuboCop/badge.svg?branch=main)](https://github.com/sashite/qi.rb/actions?query=workflow%3Arubocop+branch%3Amain)
|
7
7
|
[![License](https://img.shields.io/github/license/sashite/qi.rb?label=License&logo=github)](https://github.com/sashite/qi.rb/raw/main/LICENSE.md)
|
8
8
|
|
9
|
-
|
9
|
+
Welcome to `Qi` (Chinese: 棋; pinyin: _qí_), a flexible and customizable library designed to represent and manipulate board game positions. `Qi` is ideal for a variety of board games, including chess, shogi, xiangqi, makruk, and more.
|
10
|
+
|
11
|
+
With `Qi`, you can easily track the game state, including which pieces are on the board and where, as well as any captured pieces. The library allows for the application of game moves, updating the state of the game and generating a new position, all while preserving the original state.
|
12
|
+
|
13
|
+
## Features:
|
14
|
+
|
15
|
+
- **Flexible representation of game states:** `Qi`'s design allows it to adapt to different games with varying rules and pieces.
|
16
|
+
- **Immutable positions:** Every move generates a new position, preserving the original one. This is particularly useful for scenarios like undoing moves or exploring potential future states in the game.
|
17
|
+
- **Compact serialization:** `Qi` provides a compact string serialization method for game states, which is useful for saving game progress or transmitting game states over the network.
|
18
|
+
- **Check state tracking:** In addition to the positions and captured pieces, `Qi` also allows tracking of specific game states such as check in chess.
|
19
|
+
|
20
|
+
While `Qi` does not generate game moves itself, it serves as a solid foundation upon which game engines can be built. Its design is focused on providing a robust and adaptable representation of game states, paving the way for the development of diverse board game applications.
|
10
21
|
|
11
22
|
## Installation
|
12
23
|
|
13
24
|
Add this line to your application's Gemfile:
|
14
25
|
|
15
26
|
```ruby
|
16
|
-
gem "qi", ">= 10.0.0.
|
27
|
+
gem "qi", ">= 10.0.0.beta12"
|
17
28
|
```
|
18
29
|
|
19
30
|
And then execute:
|
@@ -33,42 +44,40 @@ gem install qi --pre
|
|
33
44
|
```ruby
|
34
45
|
require "qi"
|
35
46
|
|
36
|
-
is_north_turn = false
|
37
47
|
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
48
|
south_captures = %w[S]
|
49
|
+
captures = north_captures + south_captures
|
39
50
|
squares = { 3 => "s", 4 => "k", 5 => "s", 22 => "+P", 43 => "+B" }
|
40
51
|
|
41
|
-
qi0 = Qi.new(
|
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 # => "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>"
|
52
|
+
qi0 = Qi.new(*captures, **squares)
|
50
53
|
|
54
|
+
qi0.captures # => ["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"]
|
55
|
+
qi0.squares # => {3=>"s", 4=>"k", 5=>"s", 22=>"+P", 43=>"+B"}
|
56
|
+
qi0.in_check? # => false
|
57
|
+
qi0.not_in_check? # => true
|
58
|
+
qi0.north_turn? # => false
|
59
|
+
qi0.south_turn? # => true
|
60
|
+
qi0.serialize # => "{ 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 s@3;k@4;s@5;+P@22;+B@43 ."
|
61
|
+
qi0.inspect # => "<Qi { 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 s@3;k@4;s@5;+P@22;+B@43 .>"
|
51
62
|
qi0.to_a
|
52
63
|
# [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"],
|
64
|
+
# ["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"],
|
55
65
|
# {3=>"s", 4=>"k", 5=>"s", 22=>"+P", 43=>"+B"},
|
56
66
|
# false]
|
57
67
|
|
58
|
-
qi1 = qi0.commit(
|
59
|
-
|
60
|
-
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
|
-
qi1.south_captures # => ["S"]
|
62
|
-
qi1.squares # => {3=>"s", 4=>"k", 5=>"s", 22=>"+P", 13=>"+B"}
|
63
|
-
qi1.north_turn? # => true
|
64
|
-
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>"
|
68
|
+
qi1 = qi0.commit(is_in_check: true, 43 => nil, 13 => "+B")
|
67
69
|
|
70
|
+
qi1.captures # => ["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"]
|
71
|
+
qi1.squares # => {3=>"s", 4=>"k", 5=>"s", 22=>"+P", 13=>"+B"}
|
72
|
+
qi1.in_check? # => true
|
73
|
+
qi1.not_in_check? # => false
|
74
|
+
qi1.north_turn? # => true
|
75
|
+
qi1.south_turn? # => false
|
76
|
+
qi1.serialize # => "} 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 s@3;k@4;s@5;+B@13;+P@22 +"
|
77
|
+
qi1.inspect # => "<Qi } 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 s@3;k@4;s@5;+B@13;+P@22 +>"
|
68
78
|
qi1.to_a
|
69
79
|
# [true,
|
70
|
-
# ["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
|
-
# ["S"],
|
80
|
+
# ["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"],
|
72
81
|
# {3=>"s", 4=>"k", 5=>"s", 22=>"+P", 13=>"+B"},
|
73
82
|
# true]
|
74
83
|
```
|
data/lib/qi.rb
CHANGED
@@ -1,263 +1,132 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "digest"
|
4
|
-
|
4
|
+
require "kernel/boolean"
|
5
5
|
|
6
|
-
# The Qi class represents
|
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
|
+
# The Qi class represents a state of games such as Shogi.
|
9
7
|
class Qi
|
10
|
-
#
|
11
|
-
|
8
|
+
# @return [Array] the pieces captured by the current player.
|
9
|
+
attr_reader :captures
|
12
10
|
|
13
|
-
#
|
14
|
-
South = "South"
|
15
|
-
|
16
|
-
# @!attribute [r] north_captures
|
17
|
-
# @return [Array] The list of pieces captured by the North player.
|
18
|
-
attr_reader :north_captures
|
19
|
-
|
20
|
-
# @!attribute [r] south_captures
|
21
|
-
# @return [Array] The list of pieces captured by the South player.
|
22
|
-
attr_reader :south_captures
|
23
|
-
|
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.
|
11
|
+
# @return [Hash] the current state of the board.
|
26
12
|
attr_reader :squares
|
27
13
|
|
28
|
-
# Initializes a new
|
29
|
-
#
|
30
|
-
# @param
|
31
|
-
# @param
|
32
|
-
# @param
|
33
|
-
# @param
|
34
|
-
# @param
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
14
|
+
# Initializes a new game state.
|
15
|
+
#
|
16
|
+
# @param capture [String, nil] the piece to be captured.
|
17
|
+
# @param captures [Array] the pieces already captured.
|
18
|
+
# @param drop [String, nil] the piece to be dropped.
|
19
|
+
# @param is_in_check [Boolean] whether the current player is in check.
|
20
|
+
# @param is_north_turn [Boolean] whether it's North's turn.
|
21
|
+
# @param squares [Hash] the current state of the board.
|
22
|
+
def initialize(capture = nil, *captures, drop: nil, is_in_check: false, is_north_turn: false, **squares)
|
23
|
+
captures << capture unless capture.nil?
|
24
|
+
captures.delete_at(captures.rindex(drop)) unless drop.nil?
|
25
|
+
|
26
|
+
@captures = captures.sort
|
27
|
+
@is_in_check = Boolean(is_in_check)
|
28
|
+
@is_north_turn = Boolean(is_north_turn)
|
39
29
|
@squares = squares.compact
|
40
|
-
@is_in_check = is_in_check
|
41
|
-
end
|
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
|
58
|
-
|
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)
|
62
|
-
end
|
63
|
-
|
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.
|
66
|
-
#
|
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.
|
69
|
-
def eql?(other)
|
70
|
-
return false unless other.respond_to?(:serialize)
|
71
|
-
|
72
|
-
other.serialize == serialize
|
73
30
|
end
|
74
|
-
alias == eql?
|
75
31
|
|
76
|
-
#
|
32
|
+
# Commits a move and returns a new game state.
|
77
33
|
#
|
78
|
-
# @
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
34
|
+
# @param capture [String, nil] the piece to be captured.
|
35
|
+
# @param drop [String, nil] the piece to be dropped.
|
36
|
+
# @param is_in_check [Boolean] whether the current player is in check.
|
37
|
+
# @param diffs [Hash] the differences in the state of the board.
|
38
|
+
# @return [Qi] the new game state.
|
39
|
+
def commit(capture: nil, drop: nil, is_in_check: false, **diffs)
|
40
|
+
self.class.new(capture, *captures, drop:, is_in_check:, is_north_turn: south_turn?, **squares.merge(diffs))
|
85
41
|
end
|
86
42
|
|
87
|
-
#
|
88
|
-
|
89
|
-
|
90
|
-
def opponent_captures
|
91
|
-
if north_turn?
|
92
|
-
south_captures
|
93
|
-
else
|
94
|
-
north_captures
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
# Returns the name of the current side.
|
99
|
-
#
|
100
|
-
# @return [String] "North" if it's North's turn, "South" otherwise.
|
101
|
-
def current_turn
|
102
|
-
if north_turn?
|
103
|
-
North
|
104
|
-
else
|
105
|
-
South
|
106
|
-
end
|
43
|
+
# @return [Boolean] whether the current player is in check.
|
44
|
+
def in_check?
|
45
|
+
@is_in_check
|
107
46
|
end
|
108
47
|
|
109
|
-
#
|
110
|
-
|
111
|
-
|
112
|
-
# @return [String] "South" if it's North's turn, "North" otherwise.
|
113
|
-
def next_turn
|
114
|
-
if north_turn?
|
115
|
-
South
|
116
|
-
else
|
117
|
-
North
|
118
|
-
end
|
48
|
+
# @return [Boolean] whether the current player is not in check.
|
49
|
+
def not_in_check?
|
50
|
+
!in_check?
|
119
51
|
end
|
120
52
|
|
121
|
-
#
|
122
|
-
#
|
123
|
-
# @return [Boolean] True if it's North's turn, false otherwise.
|
53
|
+
# @return [Boolean] whether it's North's turn.
|
124
54
|
def north_turn?
|
125
55
|
@is_north_turn
|
126
56
|
end
|
127
57
|
|
128
|
-
#
|
129
|
-
#
|
130
|
-
# @return [Boolean] True if it's South's turn, false otherwise.
|
58
|
+
# @return [Boolean] whether it's South's turn.
|
131
59
|
def south_turn?
|
132
60
|
!north_turn?
|
133
61
|
end
|
134
62
|
|
135
|
-
#
|
136
|
-
|
137
|
-
|
138
|
-
def in_check?
|
139
|
-
@is_in_check
|
140
|
-
end
|
63
|
+
# @return [Boolean] whether the other game state is equal to this one.
|
64
|
+
def eql?(other)
|
65
|
+
return false unless other.respond_to?(:serialize)
|
141
66
|
|
142
|
-
|
143
|
-
#
|
144
|
-
# @return [Boolean] True if the current player is not in check, false otherwise.
|
145
|
-
def not_in_check?
|
146
|
-
!in_check?
|
67
|
+
other.serialize == serialize
|
147
68
|
end
|
69
|
+
alias == eql?
|
148
70
|
|
149
|
-
#
|
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.
|
71
|
+
# @return [Array] the array representation of the game state.
|
161
72
|
def to_a
|
162
73
|
[
|
163
74
|
north_turn?,
|
164
|
-
|
165
|
-
south_captures,
|
75
|
+
captures,
|
166
76
|
squares,
|
167
77
|
in_check?
|
168
78
|
]
|
169
79
|
end
|
170
80
|
|
171
|
-
#
|
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.
|
81
|
+
# @return [Hash] the hash representation of the game state.
|
183
82
|
def to_h
|
184
83
|
{
|
185
|
-
is_north_turn:
|
186
|
-
|
187
|
-
south_captures:,
|
84
|
+
is_north_turn: north_turn?,
|
85
|
+
captures:,
|
188
86
|
squares:,
|
189
|
-
is_in_check:
|
87
|
+
is_in_check: in_check?
|
190
88
|
}
|
191
89
|
end
|
192
90
|
|
193
|
-
#
|
91
|
+
# @return [String] the SHA-256 hash of the serialized game state.
|
194
92
|
def hash
|
195
93
|
::Digest::SHA256.hexdigest(serialize)
|
196
94
|
end
|
197
95
|
|
198
|
-
#
|
199
|
-
#
|
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.
|
209
|
-
#
|
210
|
-
# @return [String] The serialized game state.
|
96
|
+
# @return [String] the string representation of the game state.
|
211
97
|
def serialize
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
"
|
98
|
+
[
|
99
|
+
serialized_turn,
|
100
|
+
serialized_captures,
|
101
|
+
serialized_squares,
|
102
|
+
serialized_in_check
|
103
|
+
].join(" ")
|
218
104
|
end
|
219
105
|
|
220
|
-
#
|
221
|
-
#
|
222
|
-
# @return [String] A string representation of the game state.
|
106
|
+
# @return [String] the string representation of the object.
|
223
107
|
def inspect
|
224
108
|
"<#{self.class} #{serialize}>"
|
225
109
|
end
|
226
110
|
|
227
111
|
private
|
228
112
|
|
229
|
-
#
|
230
|
-
|
231
|
-
|
232
|
-
|
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:)
|
238
|
-
return [north_captures, south_captures] if in_hand.nil?
|
239
|
-
|
240
|
-
captures = if is_drop
|
241
|
-
remove_from_captures(in_hand, *current_captures)
|
242
|
-
else
|
243
|
-
current_captures + [in_hand]
|
244
|
-
end
|
113
|
+
# @return [String] the serialized turn.
|
114
|
+
def serialized_turn
|
115
|
+
north_turn? ? "}" : "{"
|
116
|
+
end
|
245
117
|
|
246
|
-
|
118
|
+
# @return [String] the serialized captures.
|
119
|
+
def serialized_captures
|
120
|
+
captures.join(";")
|
247
121
|
end
|
248
122
|
|
249
|
-
#
|
250
|
-
|
251
|
-
|
252
|
-
|
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.
|
256
|
-
def remove_from_captures(piece, *captures)
|
257
|
-
index = captures.rindex(piece)
|
258
|
-
raise Error::Drop, "There are no #{piece} in hand" if index.nil?
|
123
|
+
# @return [String] the serialized board state.
|
124
|
+
def serialized_squares
|
125
|
+
squares.keys.sort.map { |i| "#{squares.fetch(i)}@#{i}" }.join(";")
|
126
|
+
end
|
259
127
|
|
260
|
-
|
261
|
-
|
128
|
+
# @return [String] the serialized check state.
|
129
|
+
def serialized_in_check
|
130
|
+
in_check? ? "+" : "."
|
262
131
|
end
|
263
132
|
end
|
metadata
CHANGED
@@ -1,16 +1,31 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: qi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 10.0.0.
|
4
|
+
version: 10.0.0.beta12
|
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-
|
12
|
-
dependencies:
|
13
|
-
|
11
|
+
date: 2023-05-13 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: kernel-boolean
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
description: A flexible and customizable library for representing and manipulating
|
28
|
+
game states, ideal for developing board games like chess, shogi, or xiangqi.
|
14
29
|
email: contact@cyril.email
|
15
30
|
executables: []
|
16
31
|
extensions: []
|
@@ -19,7 +34,6 @@ files:
|
|
19
34
|
- LICENSE.md
|
20
35
|
- README.md
|
21
36
|
- lib/qi.rb
|
22
|
-
- lib/qi/error/drop.rb
|
23
37
|
homepage: https://github.com/sashite/qi.rb
|
24
38
|
licenses:
|
25
39
|
- MIT
|
@@ -43,5 +57,5 @@ requirements: []
|
|
43
57
|
rubygems_version: 3.4.10
|
44
58
|
signing_key:
|
45
59
|
specification_version: 4
|
46
|
-
summary:
|
60
|
+
summary: Versatile Board Game Position Representation
|
47
61
|
test_files: []
|
data/lib/qi/error/drop.rb
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class Qi
|
4
|
-
# The Error module contains custom error classes for the Qi game.
|
5
|
-
module Error
|
6
|
-
# The Drop class is a custom error class that inherits from IndexError.
|
7
|
-
# It is raised when a drop operation in the game of Qi is invalid.
|
8
|
-
#
|
9
|
-
# @see IndexError
|
10
|
-
class Drop < ::IndexError
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|