mail_chess 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|