chess_rb 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fa3d318cecdbf7ca433d3dbd4a05f865d6acd390
4
- data.tar.gz: 0674fc6547bed63a77ad029af20815221f1731c7
3
+ metadata.gz: 1584e23695704e645f8088827c43f71e60c9ce07
4
+ data.tar.gz: 9ebf999832dee1ff44b892126e558bb1675369d6
5
5
  SHA512:
6
- metadata.gz: 0fbc9bf5696a3b468989ee3b00b151f9e36ca6a84ab4a6e3249c3313e6e1ff2be8c25fdf9a5b63d9c4ed05f36600ba897fba4c7aea9daa25afc7d837068ae1eb
7
- data.tar.gz: 7dc55e6ddb44420f5ff44c0abe1c5aced4243015ecfa195a5888bb3e8a232a4a1b29cb3eb636bf7ca7294493433b5b302857fd172f64cb3c06d10bbd3d927753
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
- FILE_TO_NUM = [nil, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
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? String
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
- return valid? && ChessRB::Piece.new(@board.piece_on(@to)).type == 'k' &&
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? && ChessRB::Piece.new(@board.piece_on(@to)).type == 'k' &&
49
- (from_file - to_file).abs == 2
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) != 0
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 FILE_TO_NUM.index(square[0])
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
@@ -1,7 +1,7 @@
1
1
  class ChessRB::Notation
2
2
  def self.square_to_algebraic(move)
3
3
  board = move.board
4
- piece = ChessRB::Piece.new(board.piece_on(move.from))
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
- san = "O-O-O"
12
+ return "O-O-O"
13
13
  elsif move.king_castle?
14
- san = "O-O"
14
+ return "O-O"
15
15
  else
16
- if piece.type == 'p'
16
+ if piece.type == 'P'
17
17
  if move.capture?
18
- san = file_to_char(move.from_file)
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
- =begin
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
@@ -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
- attr_accessor :code
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.to_desc[-1, 1]
15
+ self.desc[-1, 1]
13
16
  end
14
17
 
15
- def to_desc
16
- return ChessRB::Piece.constants.select{
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(p, d)
22
+ def to_s(d)
21
23
  case @code
22
24
  when WP
23
25
  d ? "♟" : "♙"
@@ -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
- file = ChessRB::Move.file(square)
18
- rank = ChessRB::Move.rank(square)
19
- return @board[8 - rank][file - 1]
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
- # TODO
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
- # TODO
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.code_to_s(s, dark_background)
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.1
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-16 00:00:00.000000000 Z
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