chess_rb 0.0.1 → 0.0.2
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.
- checksums.yaml +4 -4
- data/lib/chess_rb/move.rb +12 -13
- data/lib/chess_rb/notation.rb +8 -8
- data/lib/chess_rb/piece.rb +8 -6
- data/lib/chess_rb/position.rb +151 -7
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1584e23695704e645f8088827c43f71e60c9ce07
|
|
4
|
+
data.tar.gz: 9ebf999832dee1ff44b892126e558bb1675369d6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cd5db4e7c13262c0076171467f2de6b16862fe844e1ab5f69b76a0776bc7b5562b71a8f2d059c2780f06f35aa7e0487f10962aa5400ae3201eeaff1937d7e49c
|
|
7
|
+
data.tar.gz: 9366f64fe308afc5e1d655cbf24a580b9702c8ff34e63cc2e19239486912f0916a42714079ef83b48ff6ad191ae52672c389993b834771573f93d967f23ed610
|
data/lib/chess_rb/move.rb
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
class ChessRB::Move
|
|
2
|
-
|
|
2
|
+
FILE_CONV = [nil, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
|
|
3
3
|
|
|
4
4
|
attr_reader :to, :from, :promotion, :square, :san, :board
|
|
5
5
|
|
|
@@ -10,7 +10,7 @@ class ChessRB::Move
|
|
|
10
10
|
@san = move
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
-
if pos.is_a?
|
|
13
|
+
if pos.is_a?(String)
|
|
14
14
|
@board = ChessRB::Position.new pos
|
|
15
15
|
else
|
|
16
16
|
@board = pos
|
|
@@ -38,20 +38,19 @@ class ChessRB::Move
|
|
|
38
38
|
|
|
39
39
|
# Returns true if move represents a queen-side castle, false otherwise.
|
|
40
40
|
def queen_castle?
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
(from_file - to_file).abs == 3
|
|
41
|
+
return valid? && @board.piece_on(@from).type == 'K' &&
|
|
42
|
+
from_file - to_file == 2
|
|
44
43
|
end
|
|
45
44
|
|
|
46
45
|
# Returns true if move represents a king-side castle, false otherwise.
|
|
47
46
|
def king_castle?
|
|
48
|
-
return valid? &&
|
|
49
|
-
|
|
47
|
+
return valid? && @board.piece_on(@from).type == 'K' &&
|
|
48
|
+
to_file - from_file == 2
|
|
50
49
|
end
|
|
51
50
|
|
|
52
51
|
# Returns true if move results in a capture, false otherwise.
|
|
53
52
|
def capture?
|
|
54
|
-
return valid? && @board.piece_on(@to) !=
|
|
53
|
+
return valid? && @board.piece_on(@to).desc != 'E'
|
|
55
54
|
end
|
|
56
55
|
|
|
57
56
|
# Returns the rank of a given square
|
|
@@ -61,26 +60,26 @@ class ChessRB::Move
|
|
|
61
60
|
|
|
62
61
|
# Returns rank of this move's @to square
|
|
63
62
|
def to_rank
|
|
64
|
-
return self.rank(@to)
|
|
63
|
+
return self.class.rank(@to)
|
|
65
64
|
end
|
|
66
65
|
|
|
67
66
|
# Returns rank of this move's @from square
|
|
68
67
|
def from_rank
|
|
69
|
-
return self.rank(@from)
|
|
68
|
+
return self.class.rank(@from)
|
|
70
69
|
end
|
|
71
70
|
|
|
72
71
|
# Returns the file of a given square as a number (e.g., a = 1, b = 2, ...)
|
|
73
72
|
def self.file(square)
|
|
74
|
-
return
|
|
73
|
+
return FILE_CONV.index(square[0])
|
|
75
74
|
end
|
|
76
75
|
|
|
77
76
|
# Returns file of this move's @to square
|
|
78
77
|
def to_file
|
|
79
|
-
return self.file(@to)
|
|
78
|
+
return self.class.file(@to)
|
|
80
79
|
end
|
|
81
80
|
|
|
82
81
|
# Returns file of this move's @from square
|
|
83
82
|
def from_file
|
|
84
|
-
return self.file(@from)
|
|
83
|
+
return self.class.file(@from)
|
|
85
84
|
end
|
|
86
85
|
end
|
data/lib/chess_rb/notation.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
class ChessRB::Notation
|
|
2
2
|
def self.square_to_algebraic(move)
|
|
3
3
|
board = move.board
|
|
4
|
-
piece =
|
|
4
|
+
piece = board.piece_on(move.from)
|
|
5
5
|
san = ""
|
|
6
6
|
|
|
7
7
|
raise ArgumentError.new "Invalid move and/or position" if !move.valid? ||
|
|
@@ -9,16 +9,17 @@ class ChessRB::Notation
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
if move.queen_castle?
|
|
12
|
-
|
|
12
|
+
return "O-O-O"
|
|
13
13
|
elsif move.king_castle?
|
|
14
|
-
|
|
14
|
+
return "O-O"
|
|
15
15
|
else
|
|
16
|
-
if piece.type == '
|
|
16
|
+
if piece.type == 'P'
|
|
17
17
|
if move.capture?
|
|
18
|
-
san =
|
|
18
|
+
san = move.from[0]
|
|
19
19
|
end
|
|
20
20
|
else
|
|
21
21
|
san += piece.type.upcase
|
|
22
|
+
|
|
22
23
|
# test ambiguities
|
|
23
24
|
# file
|
|
24
25
|
# rank
|
|
@@ -34,13 +35,12 @@ class ChessRB::Notation
|
|
|
34
35
|
|
|
35
36
|
san += "=#{move.promotion}" if move.promotion
|
|
36
37
|
|
|
37
|
-
=
|
|
38
|
+
undo_info = board.piece_on(move.to)
|
|
38
39
|
board.make_move(move)
|
|
39
40
|
if (board.check?)
|
|
40
41
|
san += board.mate? ? "#" : "+"
|
|
41
42
|
end
|
|
42
|
-
board.undo_move(move)
|
|
43
|
-
=end
|
|
43
|
+
board.undo_move(move, undo_info)
|
|
44
44
|
|
|
45
45
|
return san
|
|
46
46
|
end
|
data/lib/chess_rb/piece.rb
CHANGED
|
@@ -1,23 +1,25 @@
|
|
|
1
1
|
class ChessRB::Piece
|
|
2
|
+
E = 0
|
|
2
3
|
WP = 1; WN = 2; WLB = 3; WDB = 4; WR = 5; WQ = 6; WK = 7
|
|
3
4
|
BP = 11; BN = 12; BLB = 13; BDB = 14; BR = 15; BQ = 16; BK = 17
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
attr_reader :code, :desc
|
|
6
7
|
|
|
7
8
|
def initialize(code)
|
|
8
9
|
@code = code
|
|
10
|
+
@desc = ChessRB::Piece.constants.select{
|
|
11
|
+
|v| ChessRB::Piece.const_get(v) == code }[0].to_s
|
|
9
12
|
end
|
|
10
13
|
|
|
11
14
|
def type
|
|
12
|
-
self.
|
|
15
|
+
self.desc[-1, 1]
|
|
13
16
|
end
|
|
14
17
|
|
|
15
|
-
def
|
|
16
|
-
|
|
17
|
-
|v| ChessRB::Piece.const_get(v) == @code }[0].to_s
|
|
18
|
+
def color
|
|
19
|
+
self.desc[0]
|
|
18
20
|
end
|
|
19
21
|
|
|
20
|
-
def to_s(
|
|
22
|
+
def to_s(d)
|
|
21
23
|
case @code
|
|
22
24
|
when WP
|
|
23
25
|
d ? "♟" : "♙"
|
data/lib/chess_rb/position.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
require 'matrix'
|
|
2
|
+
|
|
1
3
|
class ChessRB::Position
|
|
2
4
|
attr_accessor :fen
|
|
3
5
|
|
|
@@ -5,40 +7,172 @@ class ChessRB::Position
|
|
|
5
7
|
@fen = fen
|
|
6
8
|
@fen_components = fen.split(' ')
|
|
7
9
|
@board = fen_to_board(fen)
|
|
10
|
+
@valid = valid?
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def self.valid_square?(s)
|
|
14
|
+
i = s[0]; j = s[1]
|
|
15
|
+
return i.is_a?(Integer) && j.is_a?(Integer) &&
|
|
16
|
+
i >= 0 && i < 8 && j >= 0 && j < 8
|
|
8
17
|
end
|
|
9
18
|
|
|
10
19
|
# TODO
|
|
11
20
|
def valid?
|
|
21
|
+
return @valid if !@valid.nil?
|
|
12
22
|
return true
|
|
13
23
|
end
|
|
14
24
|
|
|
25
|
+
# Returns 'w' or 'b' if it is white or black's move, respectively
|
|
26
|
+
def turn
|
|
27
|
+
return @fen_components[1]
|
|
28
|
+
end
|
|
29
|
+
|
|
15
30
|
# Returns the piece code on the given square
|
|
16
31
|
def piece_on(square)
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
32
|
+
if square.is_a?(String)
|
|
33
|
+
file = ChessRB::Move.file(square)
|
|
34
|
+
rank = ChessRB::Move.rank(square)
|
|
35
|
+
return ChessRB::Piece.new(@board[8 - rank][file - 1])
|
|
36
|
+
else
|
|
37
|
+
return ChessRB::Piece.new(@board[square[0]][square[1]])
|
|
38
|
+
end
|
|
20
39
|
end
|
|
21
40
|
|
|
22
|
-
|
|
41
|
+
def squares_with(piece)
|
|
42
|
+
squares = []
|
|
43
|
+
code = ChessRB::Piece.const_get(piece)
|
|
44
|
+
|
|
45
|
+
@board.each_with_index do |r , i|
|
|
46
|
+
r.each_with_index do |p, j|
|
|
47
|
+
if p == code
|
|
48
|
+
squares << [i, j]
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
return squares
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Returns if the current position is check, false otherwise
|
|
23
57
|
def check?
|
|
58
|
+
raise RuntimeError "Invalid Position" if !valid?
|
|
59
|
+
|
|
60
|
+
t = turn().upcase
|
|
61
|
+
not_t = t == 'W' ? 'B' : 'W'
|
|
62
|
+
king_vector = Vector[*(squares_with(t + 'K')[0])]
|
|
63
|
+
|
|
64
|
+
# check pawn squares
|
|
65
|
+
pawn_vectors = t == 'W' ? [[-1, -1], [1, -1]] : [[-1, 1], [1, 1]]
|
|
66
|
+
pawn_vectors.each do |s|
|
|
67
|
+
s = (king_vector + Vector[*s]).to_a
|
|
68
|
+
next if !self.class.valid_square?(s)
|
|
69
|
+
return true if piece_on(s).desc == (not_t + 'P')
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# check knight squares
|
|
73
|
+
knight_vectors = [[1,2], [-1,2], [1,-2], [-1,-2], [2,1], [-2,1], [2,-1],
|
|
74
|
+
[-2,-1]]
|
|
75
|
+
knight_vectors.each do |s|
|
|
76
|
+
s = (king_vector + Vector[*s]).to_a
|
|
77
|
+
next if !self.class.valid_square?(s)
|
|
78
|
+
return true if piece_on(s).desc == (not_t + 'N')
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# check bishop/queen squares
|
|
82
|
+
diagonal_vectors = [[1, 1], [-1, 1], [1, -1], [-1, -1]]
|
|
83
|
+
diagonal_vectors.each do |v|
|
|
84
|
+
dist = 1
|
|
85
|
+
v = Vector[*v]
|
|
86
|
+
while dist < 8
|
|
87
|
+
current_vector = v * dist
|
|
88
|
+
current_square = (king_vector + current_vector).to_a
|
|
89
|
+
|
|
90
|
+
break if !self.class.valid_square?(current_square)
|
|
91
|
+
|
|
92
|
+
p = piece_on(current_square).desc
|
|
93
|
+
return true if p == (not_t + 'B') || p == (not_t + 'Q')
|
|
94
|
+
break if p != 'E'
|
|
95
|
+
|
|
96
|
+
dist += 1
|
|
97
|
+
end
|
|
98
|
+
end
|
|
24
99
|
|
|
100
|
+
# check rook/queen squares
|
|
101
|
+
straight_vectors = [[1, 0], [0, 1], [-1, 0], [0, -1]]
|
|
102
|
+
straight_vectors.each do |v|
|
|
103
|
+
dist = 1
|
|
104
|
+
v = Vector[*v]
|
|
105
|
+
while dist < 8
|
|
106
|
+
current_vector = v * dist
|
|
107
|
+
current_square = (king_vector + current_vector).to_a
|
|
108
|
+
|
|
109
|
+
break if !self.class.valid_square?(current_square)
|
|
110
|
+
|
|
111
|
+
p = piece_on(current_square).desc
|
|
112
|
+
return true if p == (not_t + 'B') || p == (not_t + 'Q')
|
|
113
|
+
break if p != 'E'
|
|
114
|
+
|
|
115
|
+
dist += 1
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
return false
|
|
25
120
|
end
|
|
26
121
|
|
|
27
|
-
#
|
|
122
|
+
# Returns if the current position is checkmate, false otherwise
|
|
28
123
|
def mate?
|
|
124
|
+
return false if !check?
|
|
125
|
+
|
|
126
|
+
t = turn().upcase
|
|
127
|
+
king_vector = Vector[*(squares_with(t + 'K')[0])]
|
|
128
|
+
|
|
129
|
+
around_vectors = [[1, 0], [0, 1], [-1, 0], [0, -1], [1, 1], [-1, 1],
|
|
130
|
+
[1, -1], [-1, -1]]
|
|
131
|
+
around_vectors.each do |v|
|
|
132
|
+
v = Vector[*v]
|
|
133
|
+
current_square = (king_vector + v).to_a
|
|
134
|
+
if !self.class.valid_square?(current_square) ||
|
|
135
|
+
piece_on(current_square).color == t
|
|
136
|
+
|
|
137
|
+
next
|
|
138
|
+
else
|
|
139
|
+
undo_code = piece_on(current_square).code
|
|
140
|
+
move(king_vector.to_a, current_square)
|
|
141
|
+
if !check?
|
|
142
|
+
undo(king_vector.to_a, current_square, undo_code)
|
|
143
|
+
return false
|
|
144
|
+
end
|
|
145
|
+
undo(king_vector.to_a, current_square, undo_code)
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
return true
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def make_move(move)
|
|
153
|
+
move([8 - move.from_rank, move.from_file - 1],
|
|
154
|
+
[8 - move.to_rank, move.to_file - 1])
|
|
155
|
+
|
|
156
|
+
@fen_components[1] = @fen_components[1] == 'w' ? 'b' : 'w'
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def undo_move(move, piece)
|
|
160
|
+
undo([8 - move.from_rank, move.from_file - 1],
|
|
161
|
+
[8 - move.to_rank, move.to_file - 1], piece.code)
|
|
29
162
|
|
|
163
|
+
@fen_components[1] = @fen_components[1] == 'w' ? 'b' : 'w'
|
|
30
164
|
end
|
|
31
165
|
|
|
32
166
|
def to_s(dark_background = true)
|
|
33
167
|
str = ""
|
|
34
|
-
board.each_with_index do |r, i|
|
|
168
|
+
@board.each_with_index do |r, i|
|
|
35
169
|
str += (8 - i).to_s + "║"
|
|
36
170
|
r.each do |s|
|
|
37
171
|
str += " "
|
|
38
172
|
if s == 0
|
|
39
173
|
str += "…"
|
|
40
174
|
else
|
|
41
|
-
str += ChessRB::Piece.
|
|
175
|
+
str += ChessRB::Piece.new(s).to_s(dark_background)
|
|
42
176
|
end
|
|
43
177
|
end
|
|
44
178
|
str += "\n"
|
|
@@ -69,4 +203,14 @@ class ChessRB::Position
|
|
|
69
203
|
end
|
|
70
204
|
return board
|
|
71
205
|
end
|
|
206
|
+
|
|
207
|
+
def move(from, to)
|
|
208
|
+
@board[to[0]][to[1]] = @board[from[0]][from[1]]
|
|
209
|
+
@board[from[0]][from[1]] = 0
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def undo(from, to, code)
|
|
213
|
+
@board[from[0]][from[1]] = @board[to[0]][to[1]]
|
|
214
|
+
@board[to[0]][to[1]] = code
|
|
215
|
+
end
|
|
72
216
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: chess_rb
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sabar Dasgupta
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2014-06-
|
|
11
|
+
date: 2014-06-20 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: Chess functions written in Ruby
|
|
14
14
|
email: sabar.dasgupta@gmail.com
|