mail_chess 0.1.0 → 0.2.0
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.
- data/lib/mail_chess/board.rb +13 -3
- data/lib/mail_chess/game.rb +48 -4
- data/lib/mail_chess/pieces/base.rb +45 -3
- data/lib/mail_chess/pieces/bishop.rb +30 -0
- data/lib/mail_chess/pieces/king.rb +59 -0
- data/lib/mail_chess/pieces/knight.rb +25 -1
- data/lib/mail_chess/pieces/pawn.rb +35 -0
- data/lib/mail_chess/pieces/queen.rb +34 -1
- data/lib/mail_chess/pieces/rook.rb +26 -1
- data/lib/mail_chess/player.rb +21 -2
- data/test/check_mate_test.rb +95 -0
- data/test/db_operations_test.rb +2 -1
- data/test/perform_move_test.rb +49 -0
- data/test/piece_moves_test.rb +266 -0
- metadata +7 -4
data/lib/mail_chess/board.rb
CHANGED
@@ -34,10 +34,13 @@ module MailChess
|
|
34
34
|
@db_entry = @db[:boards].filter(:id => board_id).first
|
35
35
|
|
36
36
|
@id = @db_entry[:id].to_i
|
37
|
+
|
37
38
|
@pieces = {}
|
38
39
|
@db[:pieces].filter(:board_id => @id).all.each do |p|
|
39
40
|
Piece::Piece.load! db, p[:id], self
|
40
41
|
end
|
42
|
+
|
43
|
+
generate_pieces_moves
|
41
44
|
end
|
42
45
|
|
43
46
|
# Checks if needed to create tables.
|
@@ -105,13 +108,16 @@ module MailChess
|
|
105
108
|
|
106
109
|
# Delete game -- +save!+ won't fix it!
|
107
110
|
def delete!
|
108
|
-
pieces.
|
109
|
-
p.delete!
|
110
|
-
end
|
111
|
+
@db[:pieces].filter(:board_id => @id).delete
|
111
112
|
|
112
113
|
# board deleted in Game class
|
113
114
|
end
|
114
115
|
|
116
|
+
# Generates the available hits and moves for every pieces.
|
117
|
+
def generate_pieces_moves
|
118
|
+
@pieces.values.each { |p| p.generate_moves }
|
119
|
+
end
|
120
|
+
|
115
121
|
# Add a new piece to board.
|
116
122
|
#
|
117
123
|
# Arguments:
|
@@ -219,4 +225,8 @@ module MailChess
|
|
219
225
|
return result
|
220
226
|
end
|
221
227
|
end
|
228
|
+
|
229
|
+
# Error for invalid moves.
|
230
|
+
class MoveError < StandardError
|
231
|
+
end
|
222
232
|
end
|
data/lib/mail_chess/game.rb
CHANGED
@@ -21,12 +21,16 @@ module MailChess
|
|
21
21
|
# Current player's color.
|
22
22
|
attr_accessor :current
|
23
23
|
|
24
|
+
# Who tries to move.
|
25
|
+
attr_reader :initiator
|
26
|
+
|
24
27
|
# Create a new Game object.
|
25
28
|
#
|
26
29
|
# Arguments:
|
27
30
|
# db: Sequel database object
|
28
31
|
# game_id: (Integer)
|
29
|
-
|
32
|
+
# initiator: (Symbol) :white or :black
|
33
|
+
def initialize db, game_id, initiator
|
30
34
|
@db = db
|
31
35
|
|
32
36
|
Game.create_tables(@db) if Game.need_to_create_tables?(@db)
|
@@ -43,6 +47,7 @@ module MailChess
|
|
43
47
|
@players[p[:color].to_sym] = Player.load!(@db, :id, p[:player_id].to_i)
|
44
48
|
end
|
45
49
|
|
50
|
+
@initiator = initiator
|
46
51
|
end
|
47
52
|
|
48
53
|
# Checks if needed to create tables.
|
@@ -103,7 +108,7 @@ module MailChess
|
|
103
108
|
:game_id => id,
|
104
109
|
:color => 'black')
|
105
110
|
|
106
|
-
return Game.new db, id
|
111
|
+
return Game.new db, id, :white
|
107
112
|
end
|
108
113
|
|
109
114
|
# Load game from database.
|
@@ -112,15 +117,16 @@ module MailChess
|
|
112
117
|
# db: Sequel database object
|
113
118
|
# filter: (Symbol) :id or :reference
|
114
119
|
# value: filters value
|
120
|
+
# initiator: (Symbol) :white or :black
|
115
121
|
#
|
116
122
|
# Returns: (Game)
|
117
|
-
def self.load! db, filter, value
|
123
|
+
def self.load! db, filter, value, initiator
|
118
124
|
raise ArgumentError unless [:id, :reference].index(filter)
|
119
125
|
dataset = db[:games].filter(filter => value)
|
120
126
|
return nil unless dataset.all.size == 1
|
121
127
|
id = dataset.first[:id]
|
122
128
|
|
123
|
-
return Game.new db, id
|
129
|
+
return Game.new db, id, initiator
|
124
130
|
end
|
125
131
|
|
126
132
|
# Save game -- update the +current+ field.
|
@@ -135,5 +141,43 @@ module MailChess
|
|
135
141
|
@db[:games].filter(:id => @id).delete
|
136
142
|
@db[:boards].filter(:id => @board.id).delete
|
137
143
|
end
|
144
|
+
|
145
|
+
# Perform the move.
|
146
|
+
#
|
147
|
+
# Arguments:
|
148
|
+
# move: (String) eg.: e2e4
|
149
|
+
#
|
150
|
+
# Exceptions:
|
151
|
+
# (MoveError) if move is invalid
|
152
|
+
# (TurnError) if this is not the requester's turn
|
153
|
+
def perform! move
|
154
|
+
from, to = move[0] + move[1], move[2] + move[3]
|
155
|
+
p = @board.pieces[from]
|
156
|
+
k = nil
|
157
|
+
|
158
|
+
@board.pieces.values.each do |piece|
|
159
|
+
k = piece if piece.type == 'king' and piece.color == @current
|
160
|
+
end
|
161
|
+
|
162
|
+
raise TurnError.new('not your turn') if @initiator != @current
|
163
|
+
raise MoveError.new('piece not exists') if p == nil
|
164
|
+
raise MoveError.new('not your piece') if p.color != @current
|
165
|
+
raise MoveError.new('invalid move') if !p.can_move?(to) & !p.can_hit?(to)
|
166
|
+
|
167
|
+
old_p = @board.pieces[to]
|
168
|
+
p.move to
|
169
|
+
|
170
|
+
raise MoveError.new('checkmate') if k.in_checkmate?
|
171
|
+
raise MoveError.new('king in check') if k.in_check?
|
172
|
+
|
173
|
+
old_p.delete! if old_p
|
174
|
+
@current = (@current == :white ? :black : :white)
|
175
|
+
@board.save!
|
176
|
+
save!
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
# Error for invalid turns.
|
181
|
+
class TurnError < StandardError
|
138
182
|
end
|
139
183
|
end
|
@@ -21,7 +21,13 @@ module MailChess
|
|
21
21
|
|
22
22
|
# HTML tag of this piece.
|
23
23
|
attr_reader :html
|
24
|
-
|
24
|
+
|
25
|
+
# Available moves.
|
26
|
+
attr_reader :moves
|
27
|
+
|
28
|
+
# Available hits.
|
29
|
+
attr_reader :hits
|
30
|
+
|
25
31
|
# Create a new Piece object.
|
26
32
|
#
|
27
33
|
# Arguments:
|
@@ -39,6 +45,8 @@ module MailChess
|
|
39
45
|
@color = @db_entry[:color].to_sym
|
40
46
|
@board = board
|
41
47
|
@board.add @db_entry[:position], self
|
48
|
+
|
49
|
+
@possibilities_generated = false
|
42
50
|
end
|
43
51
|
|
44
52
|
# Checks if needed to create tables.
|
@@ -70,6 +78,15 @@ module MailChess
|
|
70
78
|
return @board.pieces.key(self)
|
71
79
|
end
|
72
80
|
|
81
|
+
# Moves the piece.
|
82
|
+
#
|
83
|
+
# Arguments:
|
84
|
+
# to: (String) destination field
|
85
|
+
def move to
|
86
|
+
@board.pieces[to] = @board.pieces.delete(position)
|
87
|
+
@board.pieces[to].generate_moves
|
88
|
+
end
|
89
|
+
|
73
90
|
# ABSTRACT Create a new piece and add to a table.
|
74
91
|
#
|
75
92
|
# Arguments:
|
@@ -108,11 +125,36 @@ module MailChess
|
|
108
125
|
def save!
|
109
126
|
@db[:pieces].filter(:id => @id).update(:position => position)
|
110
127
|
end
|
111
|
-
|
112
|
-
# Delete piece
|
128
|
+
|
129
|
+
# Delete piece
|
113
130
|
def delete!
|
114
131
|
@db[:pieces].filter(:id => @id).delete
|
115
132
|
end
|
133
|
+
|
134
|
+
# Decide if piece can move to +field+.
|
135
|
+
#
|
136
|
+
# Arguments:
|
137
|
+
# field: (String)
|
138
|
+
#
|
139
|
+
# Returns: (Boolean)
|
140
|
+
def can_move? field
|
141
|
+
return @moves.index(field) != nil
|
142
|
+
end
|
143
|
+
|
144
|
+
# Decide if piece can hit piece on +field+.
|
145
|
+
#
|
146
|
+
# Arguments:
|
147
|
+
# field: (String)
|
148
|
+
#
|
149
|
+
# Returns: (Boolean)
|
150
|
+
def can_hit? field
|
151
|
+
return @hits.index(field) != nil
|
152
|
+
end
|
153
|
+
|
154
|
+
# Generate the possible moves.
|
155
|
+
def generate_moves
|
156
|
+
@hits, @moves = [], []
|
157
|
+
end
|
116
158
|
end
|
117
159
|
end
|
118
160
|
end
|
@@ -25,6 +25,36 @@ module MailChess
|
|
25
25
|
|
26
26
|
return Bishop.new db, id, board
|
27
27
|
end
|
28
|
+
|
29
|
+
# Generate the possible moves.
|
30
|
+
def generate_moves
|
31
|
+
super
|
32
|
+
|
33
|
+
r, c = ROWS.index(position[1]), COLS.index(position[0])
|
34
|
+
f = {:ul => false, :ur => false, :bl => false, :br => false}
|
35
|
+
|
36
|
+
(1..7).each do |i|
|
37
|
+
pos = []
|
38
|
+
pos << [:ul, COLS[c - i] + ROWS[r - i]] if
|
39
|
+
c - i >= 0 and r - i >= 0 and !f[:ul]
|
40
|
+
pos << [:ur, COLS[c - i] + ROWS[r + i]] if
|
41
|
+
c - i >= 0 and r + i <= 7 and !f[:ur]
|
42
|
+
pos << [:bl, COLS[c + i] + ROWS[r - i]] if
|
43
|
+
c + i <= 7 and r - i >= 0 and !f[:bl]
|
44
|
+
pos << [:br, COLS[c + i] + ROWS[r + i]] if
|
45
|
+
c + i <= 7 and r + i <= 7 and !f[:br]
|
46
|
+
|
47
|
+
break if pos.empty?
|
48
|
+
pos.each do |s, p|
|
49
|
+
if @board.pieces[p]
|
50
|
+
@hits << p if @board.pieces[p].color != @color
|
51
|
+
f[s] = true
|
52
|
+
else
|
53
|
+
@moves << p
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
28
58
|
end
|
29
59
|
end
|
30
60
|
end
|
@@ -25,6 +25,65 @@ module MailChess
|
|
25
25
|
|
26
26
|
return King.new db, id, board
|
27
27
|
end
|
28
|
+
|
29
|
+
# Generate the possible moves.
|
30
|
+
def generate_moves
|
31
|
+
super
|
32
|
+
|
33
|
+
r, c = ROWS.index(position[1]), COLS.index(position[0])
|
34
|
+
(r - 1..r + 1).each do |y|
|
35
|
+
(c - 1..c + 1).each do |x|
|
36
|
+
if x >= 0 and x <= 7 and y >= 0 and y <= 7
|
37
|
+
f = COLS[x] + ROWS[y]
|
38
|
+
if @board.pieces[f] # is there a piece
|
39
|
+
@hits << f
|
40
|
+
else
|
41
|
+
@moves << f
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
@hits.delete(position)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Decide wether this king is in check.
|
51
|
+
#
|
52
|
+
# Returns: (Boolean)
|
53
|
+
def in_check?
|
54
|
+
@board.pieces.values.each do |p|
|
55
|
+
if p.color != @color # if opponent's piece
|
56
|
+
return true if p.can_hit?(position)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
return false
|
61
|
+
end
|
62
|
+
|
63
|
+
# Decide wether this king is in checkmate. (dumb method, FIXME)
|
64
|
+
#
|
65
|
+
# Returns: (Boolean)
|
66
|
+
def in_checkmate?
|
67
|
+
return false if not in_check? # if not in even check
|
68
|
+
|
69
|
+
original = @board.pieces
|
70
|
+
|
71
|
+
@board.pieces.values.each do |p|
|
72
|
+
if p.color == @color # if player's piece
|
73
|
+
original_moves_hits = p.moves + p.hits
|
74
|
+
original_moves_hits.each do |m|
|
75
|
+
p.move m
|
76
|
+
@board.generate_pieces_moves
|
77
|
+
if not in_check?
|
78
|
+
@board.pieces = original
|
79
|
+
return false
|
80
|
+
end
|
81
|
+
@board.pieces = original
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
return true
|
86
|
+
end
|
28
87
|
end
|
29
88
|
end
|
30
89
|
end
|
@@ -25,7 +25,31 @@ module MailChess
|
|
25
25
|
|
26
26
|
return Knight.new db, id, board
|
27
27
|
end
|
28
|
+
|
29
|
+
# Generate the possible moves.
|
30
|
+
def generate_moves
|
31
|
+
super
|
32
|
+
|
33
|
+
r, c = ROWS.index(position[1]), COLS.index(position[0])
|
34
|
+
|
35
|
+
pos = []
|
36
|
+
pos << COLS[c - 1] + ROWS[r - 2] if c > 0 and r > 1
|
37
|
+
pos << COLS[c + 1] + ROWS[r - 2] if c < 7 and r > 1
|
38
|
+
pos << COLS[c - 2] + ROWS[r - 1] if c > 1 and r > 0
|
39
|
+
pos << COLS[c + 2] + ROWS[r - 1] if c < 6 and r > 0
|
40
|
+
pos << COLS[c - 2] + ROWS[r + 1] if c > 1 and r < 7
|
41
|
+
pos << COLS[c + 2] + ROWS[r + 1] if c < 6 and r < 7
|
42
|
+
pos << COLS[c - 1] + ROWS[r + 2] if c > 0 and r < 6
|
43
|
+
pos << COLS[c + 1] + ROWS[r + 2] if c < 7 and r < 6
|
44
|
+
|
45
|
+
pos.each do |p|
|
46
|
+
if @board.pieces[p]
|
47
|
+
@hits << p
|
48
|
+
else
|
49
|
+
@moves << p
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
28
53
|
end
|
29
54
|
end
|
30
55
|
end
|
31
|
-
|
@@ -25,6 +25,41 @@ module MailChess
|
|
25
25
|
|
26
26
|
return Pawn.new db, id, board
|
27
27
|
end
|
28
|
+
|
29
|
+
# Generate the possible moves.
|
30
|
+
def generate_moves
|
31
|
+
super
|
32
|
+
|
33
|
+
r, c = ROWS.index(position[1]), COLS.index(position[0])
|
34
|
+
dir = @color == :white ? -1 : 1
|
35
|
+
first_step =
|
36
|
+
((@color == :white and position[1] == 2.to_s) or
|
37
|
+
(@color == :black and position[1] == 7.to_s) ? true : false)
|
38
|
+
|
39
|
+
# moves
|
40
|
+
if (r + dir >= 0 and @color == :white) or (r + dir <= 7 and
|
41
|
+
@color == :black)
|
42
|
+
f = COLS[c] + ROWS[r + dir]
|
43
|
+
@moves << f unless @board.pieces[f]
|
44
|
+
end
|
45
|
+
|
46
|
+
if (r + dir * 2 >= 0 and @color == :white) or (r + dir * 2 <= 7 and
|
47
|
+
@color == :black)
|
48
|
+
f = COLS[c] + ROWS[r + dir * 2]
|
49
|
+
@moves << f if !@board.pieces[f] and first_step
|
50
|
+
end
|
51
|
+
|
52
|
+
# hits
|
53
|
+
[-1, 1].each do |x|
|
54
|
+
if c + x >= 0 and c + x <= 7
|
55
|
+
if (r - 1 >= 0 and @color == :white) or (r + 1 <= 7 and
|
56
|
+
@color == :black)
|
57
|
+
f = COLS[c + x] + ROWS[r + dir]
|
58
|
+
@hits << f if @board.pieces[f]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
28
63
|
end
|
29
64
|
end
|
30
65
|
end
|
@@ -25,7 +25,40 @@ module MailChess
|
|
25
25
|
|
26
26
|
return Queen.new db, id, board
|
27
27
|
end
|
28
|
+
|
29
|
+
# Generate the possible moves.
|
30
|
+
def generate_moves
|
31
|
+
super
|
32
|
+
|
33
|
+
r, c = ROWS.index(position[1]), COLS.index(position[0])
|
34
|
+
f = {:ul => false, :uc => false, :ur => false,
|
35
|
+
:ml => false, :mc => true, :mr => false,
|
36
|
+
:bl => false, :bc => false, :br => false}
|
37
|
+
|
38
|
+
(1..7).each do |i|
|
39
|
+
pos = []
|
40
|
+
{'u' => -1, 'm' => 0, 'b' => 1}.each do |y, v|
|
41
|
+
{'l' => -1, 'c' => 0, 'r' => 1}.each do |x, w|
|
42
|
+
s, cc, rr = (y + x).to_sym, c + w * i, r + v * i
|
43
|
+
if cc >= 0 and cc <= 7 and rr >= 0 and rr <= 7
|
44
|
+
pos << [s, COLS[cc] + ROWS[rr]] if !f[s]
|
45
|
+
else
|
46
|
+
f[s] = true
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
break if pos.empty?
|
52
|
+
pos.each do |s, p|
|
53
|
+
if @board.pieces[p]
|
54
|
+
@hits << p if @board.pieces[p].color != @color
|
55
|
+
f[s] = true
|
56
|
+
else
|
57
|
+
@moves << p
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
28
62
|
end
|
29
63
|
end
|
30
64
|
end
|
31
|
-
|
@@ -25,7 +25,32 @@ module MailChess
|
|
25
25
|
|
26
26
|
return Rook.new db, id, board
|
27
27
|
end
|
28
|
+
|
29
|
+
# Generate the possible moves.
|
30
|
+
def generate_moves
|
31
|
+
super
|
32
|
+
|
33
|
+
r, c = ROWS.index(position[1]), COLS.index(position[0])
|
34
|
+
f = {:u => false, :l => false, :r => false, :d => false}
|
35
|
+
|
36
|
+
(1..7).each do |i|
|
37
|
+
pos = []
|
38
|
+
pos << [:u, COLS[c] + ROWS[r - i]] if r - i >= 0 and !f[:u]
|
39
|
+
pos << [:l, COLS[c - i] + ROWS[r]] if c - i >= 0 and !f[:l]
|
40
|
+
pos << [:r, COLS[c + i] + ROWS[r]] if c + i <= 7 and !f[:r]
|
41
|
+
pos << [:d, COLS[c] + ROWS[r + i]] if r + i <= 7 and !f[:d]
|
42
|
+
|
43
|
+
break if pos.empty?
|
44
|
+
pos.each do |s, p|
|
45
|
+
if @board.pieces[p]
|
46
|
+
@hits << p if @board.pieces[p].color != @color
|
47
|
+
f[s] = true
|
48
|
+
else
|
49
|
+
@moves << p
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
28
54
|
end
|
29
55
|
end
|
30
56
|
end
|
31
|
-
|
data/lib/mail_chess/player.rb
CHANGED
@@ -72,10 +72,14 @@ module MailChess
|
|
72
72
|
# value: filters value
|
73
73
|
#
|
74
74
|
# Returns: (Player)
|
75
|
+
#
|
76
|
+
# Exceptions:
|
77
|
+
# (ArgumentError) if filter is invalid
|
78
|
+
# (PlayerError) if player not exists
|
75
79
|
def self.load! db, filter, value
|
76
80
|
raise ArgumentError unless [:id, :email].index(filter)
|
77
81
|
dataset = db[:players].filter(filter => value)
|
78
|
-
raise
|
82
|
+
raise PlayerError('player not exists') unless dataset.all.size == 1
|
79
83
|
|
80
84
|
id = dataset.first[:id]
|
81
85
|
|
@@ -88,8 +92,19 @@ module MailChess
|
|
88
92
|
# reference: (String) game reference string
|
89
93
|
#
|
90
94
|
# Returns: (Game) or nil
|
95
|
+
#
|
96
|
+
# Exceptions:
|
97
|
+
# (PlayerError) if initiator is invalid
|
91
98
|
def game reference
|
92
|
-
|
99
|
+
d = @db[:pairs]
|
100
|
+
.join(:games, :id => :game_id)
|
101
|
+
.filter(:reference => reference, :player_id => self.id)
|
102
|
+
|
103
|
+
if d.all.empty?
|
104
|
+
raise PlayerError('invalid initiator')
|
105
|
+
else
|
106
|
+
Game.load! @db, :reference, reference, d.first[:color].to_sym
|
107
|
+
end
|
93
108
|
end
|
94
109
|
|
95
110
|
# Save player -- name only
|
@@ -97,4 +112,8 @@ module MailChess
|
|
97
112
|
@db[:players].filter(:id => @id).update(:name => @name)
|
98
113
|
end
|
99
114
|
end
|
115
|
+
|
116
|
+
# Error for players.
|
117
|
+
class PlayerError < StandardError
|
118
|
+
end
|
100
119
|
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'mail_chess'
|
3
|
+
require 'sequel'
|
4
|
+
|
5
|
+
class CheckMateTest < Test::Unit::TestCase
|
6
|
+
def setup
|
7
|
+
@db = Sequel.connect 'sqlite:/'
|
8
|
+
@p1 = MailChess::Player.new!(@db, 'john@doe.net')
|
9
|
+
@p2 = MailChess::Player.new!(@db, 'jane@doe.net')
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_no_check_no_checkmate
|
13
|
+
g = MailChess::Game.new!(@db, @p1, @p2, 'test@mail')
|
14
|
+
b = g.board
|
15
|
+
|
16
|
+
k = MailChess::Piece::King.new!(@db, b, 'f2', :white)
|
17
|
+
MailChess::Piece::Queen.new!(@db, b, 'b5', :oblack)
|
18
|
+
|
19
|
+
b.generate_pieces_moves
|
20
|
+
|
21
|
+
assert !k.in_check?
|
22
|
+
assert !k.in_checkmate?
|
23
|
+
|
24
|
+
g.delete!
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_check_with_king_can_hit
|
28
|
+
g = MailChess::Game.new!(@db, @p1, @p2, 'test@mail')
|
29
|
+
b = g.board
|
30
|
+
|
31
|
+
k = MailChess::Piece::King.new!(@db, b, 'f2', :white)
|
32
|
+
MailChess::Piece::Queen.new!(@db, b, 'g3', :black)
|
33
|
+
MailChess::Piece::Rook.new!(@db, b, 'e4', :black)
|
34
|
+
MailChess::Piece::Rook.new!(@db, b, 'a1', :black)
|
35
|
+
|
36
|
+
b.generate_pieces_moves
|
37
|
+
|
38
|
+
assert k.in_check?
|
39
|
+
assert !k.in_checkmate?
|
40
|
+
|
41
|
+
g.delete!
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_check_with_king_can_move
|
45
|
+
g = MailChess::Game.new!(@db, @p1, @p2, 'test@mail')
|
46
|
+
b = g.board
|
47
|
+
|
48
|
+
k = MailChess::Piece::King.new!(@db, b, 'f2', :white)
|
49
|
+
MailChess::Piece::Rook.new!(@db, b, 'f8', :black)
|
50
|
+
|
51
|
+
b.generate_pieces_moves
|
52
|
+
|
53
|
+
assert k.in_check?
|
54
|
+
assert !k.in_checkmate?
|
55
|
+
|
56
|
+
g.delete!
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_check_with_other_piece_can_move
|
60
|
+
g = MailChess::Game.new!(@db, @p1, @p2, 'test@mail')
|
61
|
+
b = g.board
|
62
|
+
|
63
|
+
k = MailChess::Piece::King.new!(@db, b, 'f2', :white)
|
64
|
+
MailChess::Piece::Bishop.new!(@db, b, 'd3', :white)
|
65
|
+
MailChess::Piece::Rook.new!(@db, b, 'e8', :black)
|
66
|
+
MailChess::Piece::Queen.new!(@db, b, 'f8', :black)
|
67
|
+
MailChess::Piece::Rook.new!(@db, b, 'g8', :black)
|
68
|
+
|
69
|
+
b.generate_pieces_moves
|
70
|
+
|
71
|
+
assert k.in_check?
|
72
|
+
assert !k.in_checkmate?
|
73
|
+
|
74
|
+
g.delete!
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_checkmate
|
78
|
+
g = MailChess::Game.new!(@db, @p1, @p2, 'test@mail')
|
79
|
+
b = g.board
|
80
|
+
|
81
|
+
MailChess::Piece::Queen.new!(@db, b, 'a1', :black)
|
82
|
+
k = MailChess::Piece::King.new!(@db, b, 'h2', :white)
|
83
|
+
MailChess::Piece::Rook.new!(@db, b, 'c3', :black)
|
84
|
+
MailChess::Piece::Pawn.new!(@db, b, 'g3', :black)
|
85
|
+
MailChess::Piece::Knight.new!(@db, b, 'g5', :black)
|
86
|
+
MailChess::Piece::Bishop.new!(@db, b, 'b7', :black)
|
87
|
+
|
88
|
+
b.generate_pieces_moves
|
89
|
+
|
90
|
+
assert k.in_check?
|
91
|
+
assert k.in_checkmate?
|
92
|
+
|
93
|
+
g.delete!
|
94
|
+
end
|
95
|
+
end
|
data/test/db_operations_test.rb
CHANGED
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'mail_chess'
|
3
|
+
require 'sequel'
|
4
|
+
|
5
|
+
class PerformMoveTest < Test::Unit::TestCase
|
6
|
+
def setup
|
7
|
+
@db = Sequel.connect 'sqlite:/'
|
8
|
+
|
9
|
+
p1 = MailChess::Player.new!(@db, 'john@doe.net')
|
10
|
+
p2 = MailChess::Player.new!(@db, 'jane@doe.net')
|
11
|
+
|
12
|
+
g = MailChess::Game.new!(@db, p1, p2, 'abcd@mail')
|
13
|
+
g.current = :white
|
14
|
+
g.save!
|
15
|
+
|
16
|
+
MailChess::Piece::Queen.new!(@db, g.board, 'a1', :black)
|
17
|
+
MailChess::Piece::King.new!(@db, g.board, 'h2', :white)
|
18
|
+
MailChess::Piece::Rook.new!(@db, g.board, 'c3', :black)
|
19
|
+
MailChess::Piece::Knight.new!(@db, g.board, 'f4', :black)
|
20
|
+
MailChess::Piece::Pawn.new!(@db, g.board, 'g4', :black)
|
21
|
+
MailChess::Piece::Knight.new!(@db, g.board, 'a5', :black)
|
22
|
+
MailChess::Piece::Pawn.new!(@db, g.board, 'b6', :white)
|
23
|
+
MailChess::Piece::Bishop.new!(@db, g.board, 'c6', :black)
|
24
|
+
MailChess::Piece::King.new!(@db, g.board, 'h8', :black)
|
25
|
+
|
26
|
+
g.board.generate_pieces_moves
|
27
|
+
File.open('table.htm', 'w') { |f| f.write(g.board.to_html) }
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_play
|
31
|
+
# Jane tries to move but it's not her turn
|
32
|
+
g = MailChess::Player.load!(@db, :email, 'jane@doe.net').game('abcd@mail')
|
33
|
+
assert_raise(MailChess::TurnError) { g.perform! 'g4g3' }
|
34
|
+
|
35
|
+
# Joe tries to move with a not existing piece, than finds the right move
|
36
|
+
g = MailChess::Player.load!(@db, :email, 'john@doe.net').game('abcd@mail')
|
37
|
+
assert_raise(MailChess::MoveError) { g.perform! 'a6a7' }
|
38
|
+
g.perform! 'b6b7'
|
39
|
+
|
40
|
+
# Jane's turn
|
41
|
+
g = MailChess::Player.load!(@db, :email, 'jane@doe.net').game('abcd@mail')
|
42
|
+
assert_raise(MailChess::MoveError) { g.perform! 'c8c7' }
|
43
|
+
assert_raise(MailChess::MoveError) { g.perform! 'b6c5' }
|
44
|
+
assert_raise(MailChess::MoveError) { g.perform! 'c6c5' }
|
45
|
+
g.perform! 'g4g3'
|
46
|
+
|
47
|
+
# the end.
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,266 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'mail_chess'
|
3
|
+
require 'sequel'
|
4
|
+
|
5
|
+
class PieceMovesTest < Test::Unit::TestCase
|
6
|
+
def setup
|
7
|
+
@db = Sequel.connect 'sqlite:/'
|
8
|
+
@p1 = MailChess::Player.new!(@db, 'john@doe.net')
|
9
|
+
@p2 = MailChess::Player.new!(@db, 'jane@doe.net')
|
10
|
+
end
|
11
|
+
|
12
|
+
def check_moves hits, moves, piece
|
13
|
+
all = MailChess::ROWS.product(MailChess::COLS).map! do |a| a.join end
|
14
|
+
all -= hits + moves
|
15
|
+
name = piece.position + " " + piece.type
|
16
|
+
|
17
|
+
all.each do |f|
|
18
|
+
assert !piece.can_move?(f), name + " shouldn't move to " + f
|
19
|
+
assert !piece.can_hit?(f), name + " shouldn't hit " + f
|
20
|
+
end
|
21
|
+
|
22
|
+
moves.each do |f|
|
23
|
+
assert piece.can_move?(f), name + " should move to " + f
|
24
|
+
assert !piece.can_hit?(f), name + " shouldn't hit " + f
|
25
|
+
end
|
26
|
+
|
27
|
+
hits.each do |f|
|
28
|
+
assert !piece.can_move?(f), name + " shouldn't move to " + f
|
29
|
+
assert piece.can_hit?(f), name + " should hit " + f
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_bishop
|
34
|
+
g = MailChess::Game.new!(@db, @p1, @p2, 'test@mail')
|
35
|
+
b = g.board
|
36
|
+
|
37
|
+
MailChess::Piece::Bishop.new!(@db, b, 'c2', :black)
|
38
|
+
MailChess::Piece::Pawn.new!(@db, b, 'd3', :white)
|
39
|
+
MailChess::Piece::Bishop.new!(@db, b, 'g3', :black)
|
40
|
+
MailChess::Piece::Rook.new!(@db, b, 'a4', :white)
|
41
|
+
MailChess::Piece::Bishop.new!(@db, b, 'e4', :white)
|
42
|
+
MailChess::Piece::Knight.new!(@db, b, 'f4', :white)
|
43
|
+
MailChess::Piece::Pawn.new!(@db, b, 'h4', :black)
|
44
|
+
MailChess::Piece::Bishop.new!(@db, b, 'a8', :white)
|
45
|
+
|
46
|
+
b.generate_pieces_moves
|
47
|
+
|
48
|
+
# c2
|
49
|
+
hits = %w[d3 a4]
|
50
|
+
moves = %w[b1 d1 b3]
|
51
|
+
check_moves hits, moves, b.pieces['c2']
|
52
|
+
|
53
|
+
# g3
|
54
|
+
hits = %w[f4]
|
55
|
+
moves = %w[e1 f2 h2]
|
56
|
+
check_moves hits, moves, b.pieces['g3']
|
57
|
+
|
58
|
+
# e4
|
59
|
+
hits = %w[]
|
60
|
+
moves = %w[h1 g2 f3 d5 f5 c6 g6 b7 h7]
|
61
|
+
check_moves hits, moves, b.pieces['e4']
|
62
|
+
|
63
|
+
# a8
|
64
|
+
hits = %w[]
|
65
|
+
moves = %w[d5 c6 b7]
|
66
|
+
check_moves hits, moves, b.pieces['a8']
|
67
|
+
|
68
|
+
g.delete!
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_king
|
72
|
+
g = MailChess::Game.new!(@db, @p1, @p2, 'test@mail')
|
73
|
+
b = g.board
|
74
|
+
|
75
|
+
MailChess::Piece::King.new!(@db, b, 'a1', :white)
|
76
|
+
MailChess::Piece::Pawn.new!(@db, b, 'a2', :black)
|
77
|
+
MailChess::Piece::Bishop.new!(@db, b, 'd2', :black)
|
78
|
+
MailChess::Piece::King.new!(@db, b, 'e2', :black)
|
79
|
+
MailChess::Piece::Knight.new!(@db, b, 'f3', :white)
|
80
|
+
|
81
|
+
b.generate_pieces_moves
|
82
|
+
|
83
|
+
# a1
|
84
|
+
hits = %w[a2]
|
85
|
+
moves = %w[b1 b2]
|
86
|
+
check_moves hits, moves, b.pieces['a1']
|
87
|
+
|
88
|
+
# e2
|
89
|
+
hits = %w[f3]
|
90
|
+
moves = %w[d1 e1 f1 f2 d3 e3]
|
91
|
+
check_moves hits, moves, b.pieces['e2']
|
92
|
+
|
93
|
+
g.delete!
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_knight
|
97
|
+
g = MailChess::Game.new!(@db, @p1, @p2, 'test@mail')
|
98
|
+
b = g.board
|
99
|
+
|
100
|
+
MailChess::Piece::Knight.new!(@db, b, 'a2', :white)
|
101
|
+
MailChess::Piece::Pawn.new!(@db, b, 'c3', :white)
|
102
|
+
MailChess::Piece::Knight.new!(@db, b, 'f3', :black)
|
103
|
+
MailChess::Piece::Pawn.new!(@db, b, 'b4', :black)
|
104
|
+
MailChess::Piece::Knight.new!(@db, b, 'd4', :white)
|
105
|
+
MailChess::Piece::Pawn.new!(@db, b, 'h4', :black)
|
106
|
+
MailChess::Piece::Pawn.new!(@db, b, 'e6', :white)
|
107
|
+
MailChess::Piece::Knight.new!(@db, b, 'g7', :black)
|
108
|
+
|
109
|
+
b.generate_pieces_moves
|
110
|
+
|
111
|
+
# a2
|
112
|
+
hits = %w[b4]
|
113
|
+
moves = %w[c1]
|
114
|
+
check_moves hits, moves, b.pieces['a2']
|
115
|
+
|
116
|
+
# f3
|
117
|
+
hits = %w[d4]
|
118
|
+
moves = %w[e1 g1 d2 h2 e5 g5]
|
119
|
+
check_moves hits, moves, b.pieces['f3']
|
120
|
+
|
121
|
+
# d4
|
122
|
+
hits = %w[f3]
|
123
|
+
moves = %w[c2 e2 b3 b5 f5 c6]
|
124
|
+
check_moves hits, moves, b.pieces['d4']
|
125
|
+
|
126
|
+
# g7
|
127
|
+
hits = %w[e6]
|
128
|
+
moves = %w[f5 h5 e8]
|
129
|
+
check_moves hits, moves, b.pieces['g7']
|
130
|
+
|
131
|
+
g.delete!
|
132
|
+
end
|
133
|
+
|
134
|
+
def test_pawn
|
135
|
+
g = MailChess::Game.new!(@db, @p1, @p2, 'test@mail')
|
136
|
+
b = g.board
|
137
|
+
|
138
|
+
MailChess::Piece::Pawn.new!(@db, b, 'a1', :black)
|
139
|
+
MailChess::Piece::Pawn.new!(@db, b, 'c2', :white)
|
140
|
+
MailChess::Piece::Pawn.new!(@db, b, 'g2', :white)
|
141
|
+
MailChess::Piece::Rook.new!(@db, b, 'g4', :black)
|
142
|
+
MailChess::Piece::Pawn.new!(@db, b, 'a5', :white)
|
143
|
+
MailChess::Piece::Pawn.new!(@db, b, 'e5', :black)
|
144
|
+
MailChess::Piece::Pawn.new!(@db, b, 'f5', :white)
|
145
|
+
MailChess::Piece::Bishop.new!(@db, b, 'b6', :black)
|
146
|
+
MailChess::Piece::Pawn.new!(@db, b, 'f6', :black)
|
147
|
+
MailChess::Piece::Pawn.new!(@db, b, 'g6', :white)
|
148
|
+
MailChess::Piece::Pawn.new!(@db, b, 'h7', :black)
|
149
|
+
MailChess::Piece::Pawn.new!(@db, b, 'd8', :white)
|
150
|
+
|
151
|
+
b.generate_pieces_moves
|
152
|
+
|
153
|
+
# a1
|
154
|
+
hits = %w[]
|
155
|
+
moves = %w[]
|
156
|
+
check_moves hits, moves, b.pieces['a1']
|
157
|
+
|
158
|
+
# c2
|
159
|
+
hits = %w[]
|
160
|
+
moves = %w[c3 c4]
|
161
|
+
check_moves hits, moves, b.pieces['c2']
|
162
|
+
|
163
|
+
# g2
|
164
|
+
hits = %w[]
|
165
|
+
moves = %w[g3]
|
166
|
+
check_moves hits, moves, b.pieces['g2']
|
167
|
+
|
168
|
+
# a5
|
169
|
+
hits = %w[b6]
|
170
|
+
moves = %w[a6]
|
171
|
+
check_moves hits, moves, b.pieces['a5']
|
172
|
+
|
173
|
+
# e5
|
174
|
+
hits = %w[]
|
175
|
+
moves = %w[e4]
|
176
|
+
check_moves hits, moves, b.pieces['e5']
|
177
|
+
|
178
|
+
# f5
|
179
|
+
hits = %w[]
|
180
|
+
moves = %w[]
|
181
|
+
check_moves hits, moves, b.pieces['f5']
|
182
|
+
|
183
|
+
# f6
|
184
|
+
hits = %w[]
|
185
|
+
moves = %w[]
|
186
|
+
check_moves hits, moves, b.pieces['f6']
|
187
|
+
|
188
|
+
# g6
|
189
|
+
hits = %w[h7]
|
190
|
+
moves = %w[g7]
|
191
|
+
check_moves hits, moves, b.pieces['g6']
|
192
|
+
|
193
|
+
# h7
|
194
|
+
hits = %w[g6]
|
195
|
+
moves = %w[h6 h5]
|
196
|
+
check_moves hits, moves, b.pieces['h7']
|
197
|
+
|
198
|
+
# d8
|
199
|
+
hits = %w[]
|
200
|
+
moves = %w[]
|
201
|
+
check_moves hits, moves, b.pieces['d8']
|
202
|
+
|
203
|
+
g.delete!
|
204
|
+
end
|
205
|
+
|
206
|
+
def test_queen
|
207
|
+
g = MailChess::Game.new!(@db, @p1, @p2, 'test@mail')
|
208
|
+
b = g.board
|
209
|
+
|
210
|
+
MailChess::Piece::Bishop.new!(@db, b, 'g1', :white)
|
211
|
+
MailChess::Piece::Knight.new!(@db, b, 'b3', :white)
|
212
|
+
MailChess::Piece::Queen.new!(@db, b, 'e3', :black)
|
213
|
+
MailChess::Piece::Pawn.new!(@db, b, 'e5', :black)
|
214
|
+
MailChess::Piece::Knight.new!(@db, b, 'd6', :black)
|
215
|
+
MailChess::Piece::Rook.new!(@db, b, 'h6', :white)
|
216
|
+
MailChess::Piece::Queen.new!(@db, b, 'a7', :white)
|
217
|
+
MailChess::Piece::Pawn.new!(@db, b, 'f7', :white)
|
218
|
+
MailChess::Piece::Pawn.new!(@db, b, 'g7', :black)
|
219
|
+
|
220
|
+
b.generate_pieces_moves
|
221
|
+
|
222
|
+
# e3
|
223
|
+
hits = %w[g1 b3 h6 a7]
|
224
|
+
moves = %w[c1 e1 d2 e2 f2 c3 d3 f3 g3 h3 d4 e4 f4 c5 g5 b6]
|
225
|
+
check_moves hits, moves, b.pieces['e3']
|
226
|
+
|
227
|
+
# a7
|
228
|
+
hits = %w[e3]
|
229
|
+
moves = %w[a1 a2 a3 a4 d4 a5 c5 a6 b6 b7 c7 d7 e7 a8 b8]
|
230
|
+
check_moves hits, moves, b.pieces['a7']
|
231
|
+
end
|
232
|
+
|
233
|
+
def test_rook
|
234
|
+
g = MailChess::Game.new!(@db, @p1, @p2, 'test@mail')
|
235
|
+
b = g.board
|
236
|
+
|
237
|
+
MailChess::Piece::Rook.new!(@db, b, 'a3', :white)
|
238
|
+
MailChess::Piece::Knight.new!(@db, b, 'c3', :black)
|
239
|
+
MailChess::Piece::Rook.new!(@db, b, 'f4', :white)
|
240
|
+
MailChess::Piece::Pawn.new!(@db, b, 'h4', :black)
|
241
|
+
MailChess::Piece::Rook.new!(@db, b, 'c8', :black)
|
242
|
+
MailChess::Piece::Rook.new!(@db, b, 'f8', :black)
|
243
|
+
|
244
|
+
b.generate_pieces_moves
|
245
|
+
|
246
|
+
# a3
|
247
|
+
hits = %w[c3]
|
248
|
+
moves = %w[a1 a2 b3 a4 a5 a6 a7 a8]
|
249
|
+
check_moves hits, moves, b.pieces['a3']
|
250
|
+
|
251
|
+
# f4
|
252
|
+
hits = %w[f8 h4]
|
253
|
+
moves = %w[f1 f2 f3 a4 b4 c4 d4 e4 g4 f5 f6 f7]
|
254
|
+
check_moves hits, moves, b.pieces['f4']
|
255
|
+
|
256
|
+
# c8
|
257
|
+
hits = %w[]
|
258
|
+
moves = %w[c4 c5 c6 c7 a8 b8 d8 e8]
|
259
|
+
check_moves hits, moves, b.pieces['c8']
|
260
|
+
|
261
|
+
# f8
|
262
|
+
hits = %w[f4]
|
263
|
+
moves = %w[f5 f6 f7 d8 e8 g8 h8]
|
264
|
+
check_moves hits, moves, b.pieces['f8']
|
265
|
+
end
|
266
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mail_chess
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-07-
|
12
|
+
date: 2012-07-08 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: sequel
|
@@ -18,7 +18,7 @@ dependencies:
|
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version:
|
21
|
+
version: 3.37.0
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -26,7 +26,7 @@ dependencies:
|
|
26
26
|
requirements:
|
27
27
|
- - ! '>='
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version:
|
29
|
+
version: 3.37.0
|
30
30
|
description: Play chess with your friends in email!
|
31
31
|
email: karaszandris@gmail.com
|
32
32
|
executables: []
|
@@ -46,7 +46,10 @@ files:
|
|
46
46
|
- lib/mail_chess.rb
|
47
47
|
- Rakefile
|
48
48
|
- README
|
49
|
+
- test/check_mate_test.rb
|
49
50
|
- test/db_operations_test.rb
|
51
|
+
- test/piece_moves_test.rb
|
52
|
+
- test/perform_move_test.rb
|
50
53
|
homepage: http://rubygems.org/gems/mail_chess
|
51
54
|
licenses: []
|
52
55
|
post_install_message:
|