chess_game 0.0.11
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 +7 -0
- data/.rspec +1 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +58 -0
- data/README.md +24 -0
- data/Rakefile +3 -0
- data/bin/chess +3 -0
- data/chess-0.0.11.gem +0 -0
- data/chess.gemspec +29 -0
- data/game.dat +0 -0
- data/lib/chess/bishop.rb +28 -0
- data/lib/chess/board.rb +170 -0
- data/lib/chess/game.rb +73 -0
- data/lib/chess/king.rb +101 -0
- data/lib/chess/knight.rb +28 -0
- data/lib/chess/move_helper.rb +185 -0
- data/lib/chess/pawn.rb +58 -0
- data/lib/chess/piece.rb +134 -0
- data/lib/chess/player.rb +36 -0
- data/lib/chess/queen.rb +30 -0
- data/lib/chess/rook.rb +30 -0
- data/lib/chess/version.rb +3 -0
- data/lib/chess.rb +71 -0
- data/save/test +0 -0
- data/spec/bishop_spec.rb +32 -0
- data/spec/board_spec.rb +206 -0
- data/spec/game_spec.rb +32 -0
- data/spec/king_spec.rb +167 -0
- data/spec/knight_spec.rb +57 -0
- data/spec/pawn_spec.rb +144 -0
- data/spec/piece_spec.rb +43 -0
- data/spec/player_spec.rb +47 -0
- data/spec/queen_spec.rb +35 -0
- data/spec/rook_spec.rb +31 -0
- data/spec/spec_helper.rb +3 -0
- metadata +147 -0
@@ -0,0 +1,185 @@
|
|
1
|
+
class String
|
2
|
+
|
3
|
+
# "-" overloaded on string to assist in differencing algebraic notation strings
|
4
|
+
def -(next_loc)
|
5
|
+
if next_loc.length == 2 && self.length == 2
|
6
|
+
x = self[0].ord - next_loc[0].ord
|
7
|
+
y = self[1].ord - next_loc[1].ord
|
8
|
+
return x, y
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def passed?
|
13
|
+
nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def passable?
|
17
|
+
nil
|
18
|
+
end
|
19
|
+
|
20
|
+
def passable=(o)
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
|
24
|
+
def color
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
|
28
|
+
def opponent?(o = nil)
|
29
|
+
nil
|
30
|
+
end
|
31
|
+
|
32
|
+
def location
|
33
|
+
nil
|
34
|
+
end
|
35
|
+
|
36
|
+
def location=(o = nil)
|
37
|
+
nil
|
38
|
+
end
|
39
|
+
|
40
|
+
def move(o = nil, p = nil)
|
41
|
+
nil
|
42
|
+
end
|
43
|
+
|
44
|
+
def friend?(o = nil)
|
45
|
+
nil
|
46
|
+
end
|
47
|
+
|
48
|
+
def rank?
|
49
|
+
("1".."8").any? { |x| self[0] == x }
|
50
|
+
end
|
51
|
+
|
52
|
+
def file?
|
53
|
+
("A".."H").any? { |x| self[0] == x }
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
def squares_between(loc_1, loc_2)
|
60
|
+
x, y = loc_2 - loc_1
|
61
|
+
|
62
|
+
if x == y && y == 0
|
63
|
+
return nil
|
64
|
+
end
|
65
|
+
|
66
|
+
if x > 0
|
67
|
+
x_range = (loc_1[0]..loc_2[0]).to_a
|
68
|
+
elsif x < 0
|
69
|
+
x_range = (loc_2[0]..loc_1[0]).to_a.reverse
|
70
|
+
end
|
71
|
+
if y > 0
|
72
|
+
y_range = (loc_1[1]..loc_2[1]).to_a
|
73
|
+
elsif y < 0
|
74
|
+
y_range = (loc_2[1]..loc_1[1]).to_a.reverse
|
75
|
+
end
|
76
|
+
|
77
|
+
if x != 0 && y == 0
|
78
|
+
y_range = Array.new(x_range.length, loc_1[1])
|
79
|
+
elsif x == 0 && y != 0
|
80
|
+
x_range = Array.new(y_range.length, loc_1[0])
|
81
|
+
end
|
82
|
+
|
83
|
+
# zip up the ranges to made a clean list of square between
|
84
|
+
squares_between = []
|
85
|
+
x_range.zip(y_range).each { |x| squares_between << x.join }
|
86
|
+
|
87
|
+
# trim off the first and last squares
|
88
|
+
squares_between.delete_at(0)
|
89
|
+
squares_between.delete_at(-1)
|
90
|
+
return squares_between
|
91
|
+
end
|
92
|
+
|
93
|
+
def check_castle(king, board, horiz_move, vert_move)
|
94
|
+
if king.moves > 0 || horiz_move.abs != 2
|
95
|
+
return false
|
96
|
+
end
|
97
|
+
|
98
|
+
unless vert_move == 0
|
99
|
+
return false
|
100
|
+
end
|
101
|
+
|
102
|
+
if king.black?
|
103
|
+
return false unless king.location == "E8"
|
104
|
+
queen_rook = board.board["A8"]
|
105
|
+
king_rook = board.board["H8"]
|
106
|
+
horiz_move < 0 ? attack = "D8" : attack = "F8"
|
107
|
+
elsif king.white?
|
108
|
+
return false unless king.location == "E1"
|
109
|
+
queen_rook = board.board["A1"]
|
110
|
+
king_rook = board.board["H1"]
|
111
|
+
horiz_move < 0 ? attack = "D1" : attack = "F1"
|
112
|
+
else
|
113
|
+
return nil
|
114
|
+
end
|
115
|
+
|
116
|
+
# check if the square the king passes through is under attack
|
117
|
+
# place a "test king" and see if he is in check
|
118
|
+
test_king = King.new(king.color, attack)
|
119
|
+
|
120
|
+
# need to remove the old king to place a test piece
|
121
|
+
board.rv_piece(king.location)
|
122
|
+
if board[attack] == " "
|
123
|
+
board.set_piece(test_king)
|
124
|
+
else
|
125
|
+
board.set_piece(king)
|
126
|
+
return false
|
127
|
+
end
|
128
|
+
|
129
|
+
if test_king.check?(board)
|
130
|
+
board.set_piece(king)
|
131
|
+
board.rv_piece(attack)
|
132
|
+
return false
|
133
|
+
end
|
134
|
+
|
135
|
+
# remove the test piece and reset the king
|
136
|
+
board.rv_piece(attack)
|
137
|
+
board.set_piece(king)
|
138
|
+
|
139
|
+
if horiz_move < 0
|
140
|
+
queen_rook.is_a?(Rook) && queen_rook.moves == 0 ? true : (return false)
|
141
|
+
elsif horiz_move > 0
|
142
|
+
king_rook.is_a?(Rook) && king_rook.moves == 0 ? true : (return false)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
# check if a castling move was done by the king and move the complementary rook
|
147
|
+
def castle_complement(piece, board)
|
148
|
+
if piece.moves == 1
|
149
|
+
if piece.is_a?(King)
|
150
|
+
|
151
|
+
case piece.location
|
152
|
+
when "C1"
|
153
|
+
rook = board["A1"]
|
154
|
+
rook_new_loc = "D1"
|
155
|
+
when "G1"
|
156
|
+
rook = board["H1"]
|
157
|
+
rook_new_loc = "F1"
|
158
|
+
when "C8"
|
159
|
+
rook = board["A8"]
|
160
|
+
rook_new_loc = "D8"
|
161
|
+
when "G8"
|
162
|
+
rook = board["H8"]
|
163
|
+
rook_new_loc = "F8"
|
164
|
+
end
|
165
|
+
|
166
|
+
if rook.is_a?(Rook)
|
167
|
+
# pick up the king so the rook can move
|
168
|
+
board.rv_piece(piece.location)
|
169
|
+
|
170
|
+
# move the rook
|
171
|
+
|
172
|
+
board.rv_piece(rook.location)
|
173
|
+
rook.location = rook_new_loc
|
174
|
+
board.set_piece(rook)
|
175
|
+
|
176
|
+
# replace the king after
|
177
|
+
board.set_piece(piece)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
def relative_square(location, x, y)
|
184
|
+
(location[0].ord + x).chr + (location[1].ord + y).chr
|
185
|
+
end
|
data/lib/chess/pawn.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require_relative 'piece.rb'
|
2
|
+
|
3
|
+
class Pawn < Piece
|
4
|
+
|
5
|
+
WHITE_PAWN_ICON = "\u2659"
|
6
|
+
BLACK_PAWN_ICON = "\u265F"
|
7
|
+
|
8
|
+
def initialize(color = "white", location = "A1")
|
9
|
+
case color.downcase
|
10
|
+
when "white"
|
11
|
+
@icon = WHITE_PAWN_ICON
|
12
|
+
when "black"
|
13
|
+
@icon = BLACK_PAWN_ICON
|
14
|
+
end
|
15
|
+
super
|
16
|
+
end
|
17
|
+
|
18
|
+
def move(new_loc, board)
|
19
|
+
x, y = new_loc - @location
|
20
|
+
@passable = true if y.abs == 2
|
21
|
+
super
|
22
|
+
end
|
23
|
+
|
24
|
+
def valid_move?(new_loc, board)
|
25
|
+
x, y = new_loc - @location
|
26
|
+
|
27
|
+
y *= -1 if self.black?
|
28
|
+
|
29
|
+
if x == 0 && y == 1 && board[new_loc] == " "
|
30
|
+
elsif x == 0 && y == 2 && @moves == 0 && board[new_loc] == " "
|
31
|
+
elsif y == 1 && x.abs == 1 && board.board[new_loc].opponent?(self)
|
32
|
+
elsif en_passant?(new_loc, board)
|
33
|
+
else
|
34
|
+
board.move_status = "Pawns cannot make that move."
|
35
|
+
return false
|
36
|
+
end
|
37
|
+
super
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
def en_passant?(new_loc, board)
|
42
|
+
x, y = new_loc - @location
|
43
|
+
return false unless x.abs == 1 && y.abs == 1
|
44
|
+
passing_square = relative_square(@location, x, 0)
|
45
|
+
passed_piece = board[passing_square]
|
46
|
+
return false unless passed_piece.is_a?(Pawn)
|
47
|
+
# conditions for en passant, must be opposing pawn that moved forward twice to
|
48
|
+
# the square it would have occupied if it was only moved one square
|
49
|
+
if self.opponent?(passed_piece) && passed_piece.passable?
|
50
|
+
# board.rv_piece(passing_square)
|
51
|
+
passed_piece.passed = true
|
52
|
+
return passed_piece.location
|
53
|
+
else
|
54
|
+
return false
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
data/lib/chess/piece.rb
ADDED
@@ -0,0 +1,134 @@
|
|
1
|
+
require_relative 'move_helper.rb'
|
2
|
+
|
3
|
+
class Piece
|
4
|
+
|
5
|
+
def initialize(color = "white", location = 'A1')
|
6
|
+
@color = color
|
7
|
+
@location = location.upcase
|
8
|
+
@moves = 0
|
9
|
+
|
10
|
+
# for determining en passant
|
11
|
+
@passable = false
|
12
|
+
@passed = false
|
13
|
+
end
|
14
|
+
|
15
|
+
def passable?
|
16
|
+
@passable
|
17
|
+
end
|
18
|
+
|
19
|
+
def passable=(o)
|
20
|
+
@passable = o
|
21
|
+
end
|
22
|
+
|
23
|
+
def passed?
|
24
|
+
@passed
|
25
|
+
end
|
26
|
+
|
27
|
+
def passed=(o)
|
28
|
+
@passed = o
|
29
|
+
end
|
30
|
+
|
31
|
+
def moves
|
32
|
+
@moves
|
33
|
+
end
|
34
|
+
|
35
|
+
def moves=(moves)
|
36
|
+
@moves = moves
|
37
|
+
end
|
38
|
+
|
39
|
+
def color
|
40
|
+
@color
|
41
|
+
end
|
42
|
+
|
43
|
+
def location
|
44
|
+
@location
|
45
|
+
end
|
46
|
+
|
47
|
+
def file
|
48
|
+
@location[0]
|
49
|
+
end
|
50
|
+
|
51
|
+
def rank
|
52
|
+
@location[1]
|
53
|
+
end
|
54
|
+
|
55
|
+
def location=(location)
|
56
|
+
@location = location
|
57
|
+
end
|
58
|
+
|
59
|
+
def icon
|
60
|
+
@icon
|
61
|
+
end
|
62
|
+
|
63
|
+
def to_s
|
64
|
+
@icon
|
65
|
+
end
|
66
|
+
|
67
|
+
def black?
|
68
|
+
@color == "black"
|
69
|
+
end
|
70
|
+
|
71
|
+
def white?
|
72
|
+
@color == "white"
|
73
|
+
end
|
74
|
+
|
75
|
+
def opponent?(piece)
|
76
|
+
piece.color != @color
|
77
|
+
end
|
78
|
+
|
79
|
+
def friend?(piece)
|
80
|
+
piece.color == @color
|
81
|
+
end
|
82
|
+
|
83
|
+
def move(new_loc, board)
|
84
|
+
if self.valid_move?(new_loc, board)
|
85
|
+
@moves += 1
|
86
|
+
@location = new_loc
|
87
|
+
else
|
88
|
+
return nil
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def can_promote?
|
93
|
+
((@color == "white" && self.rank == "8") || (@color == "black" && self.rank == "1")) && self.is_a?(Pawn)
|
94
|
+
end
|
95
|
+
|
96
|
+
def my_king(board)
|
97
|
+
# tells a player where his beloved monarch is
|
98
|
+
board.board.each do |location, piece|
|
99
|
+
if piece.is_a?(King) && piece.color == self.color
|
100
|
+
return piece
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def valid_move?(new_loc, board)
|
106
|
+
if board[new_loc].nil?
|
107
|
+
board.move_status = "Position is off the board"
|
108
|
+
return false
|
109
|
+
elsif @location == new_loc
|
110
|
+
board.move_status = "Piece must move"
|
111
|
+
return false
|
112
|
+
elsif board.piece_between?(@location, new_loc)
|
113
|
+
board.move_status = "Piece in between move"
|
114
|
+
return false
|
115
|
+
elsif self.friend?(board[new_loc])
|
116
|
+
board.move_status = "Can't take your own piece"
|
117
|
+
return false
|
118
|
+
else
|
119
|
+
return true
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def ==(o)
|
124
|
+
o.class == self.class && o.state == state
|
125
|
+
end
|
126
|
+
alias_method :eql?, :==
|
127
|
+
|
128
|
+
protected
|
129
|
+
|
130
|
+
def state
|
131
|
+
[@color, @location, @moves]
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
data/lib/chess/player.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
class Player
|
2
|
+
|
3
|
+
def initialize(color = "white")
|
4
|
+
@color = color
|
5
|
+
end
|
6
|
+
|
7
|
+
|
8
|
+
def color
|
9
|
+
@color
|
10
|
+
end
|
11
|
+
|
12
|
+
def move(loc_1, loc_2, board)
|
13
|
+
|
14
|
+
return nil unless loc_1.is_a?(String) && loc_2.is_a?(String)
|
15
|
+
|
16
|
+
loc_1.upcase!
|
17
|
+
loc_2.upcase!
|
18
|
+
|
19
|
+
return nil unless loc_1[0].file? && loc_2[0].file? && loc_1[1].rank? && loc_2[1].rank?
|
20
|
+
if board.board[loc_1].color == @color
|
21
|
+
unless self.king(board).will_be_in_check?(loc_1, loc_2, board)
|
22
|
+
board.move(loc_1, loc_2)
|
23
|
+
else
|
24
|
+
board.move_status = "Can't put your king into Check"
|
25
|
+
return nil
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
def king(board)
|
32
|
+
king = board.board.select do |square, piece|
|
33
|
+
return piece if piece.color == self.color && piece.class == King
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/chess/queen.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require_relative 'piece.rb'
|
2
|
+
|
3
|
+
class Queen < Piece
|
4
|
+
|
5
|
+
WHITE_QUEEN_ICON = "\u2655"
|
6
|
+
BLACK_QUEEN_ICON = "\u265B"
|
7
|
+
|
8
|
+
def initialize(color = "white", location = "A1")
|
9
|
+
case color.downcase
|
10
|
+
when "white"
|
11
|
+
@icon = WHITE_QUEEN_ICON
|
12
|
+
when "black"
|
13
|
+
@icon = BLACK_QUEEN_ICON
|
14
|
+
end
|
15
|
+
super
|
16
|
+
end
|
17
|
+
|
18
|
+
def valid_move?(new_loc, board)
|
19
|
+
x, y = new_loc - @location
|
20
|
+
if x.abs == y.abs
|
21
|
+
elsif x == 0 && y.abs > 0
|
22
|
+
elsif y == 0 && x.abs > 0
|
23
|
+
else
|
24
|
+
board.move_status = "Queens cannot make that move."
|
25
|
+
return false
|
26
|
+
end
|
27
|
+
super
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
data/lib/chess/rook.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require_relative 'piece.rb'
|
2
|
+
|
3
|
+
class Rook < Piece
|
4
|
+
|
5
|
+
WHITE_ROOK_ICON = "\u2656"
|
6
|
+
BLACK_ROOK_ICON = "\u265C"
|
7
|
+
|
8
|
+
def initialize(color = "white", location = "A1")
|
9
|
+
case color.downcase
|
10
|
+
when "white"
|
11
|
+
@icon = WHITE_ROOK_ICON
|
12
|
+
when "black"
|
13
|
+
@icon = BLACK_ROOK_ICON
|
14
|
+
end
|
15
|
+
super
|
16
|
+
end
|
17
|
+
|
18
|
+
def valid_move?(new_loc, board)
|
19
|
+
x, y = new_loc - @location
|
20
|
+
|
21
|
+
if x == 0 && y.abs > 0
|
22
|
+
elsif y == 0 && x.abs > 0
|
23
|
+
else
|
24
|
+
board.move_status = "Rooks cannot make that move."
|
25
|
+
return false
|
26
|
+
end
|
27
|
+
super
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
data/lib/chess.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
require_relative 'chess/board.rb'
|
2
|
+
|
3
|
+
module Chess
|
4
|
+
def self.play
|
5
|
+
@game = Game.new
|
6
|
+
|
7
|
+
@board = @game.board
|
8
|
+
|
9
|
+
players = [@game.white_player, @game.black_player]
|
10
|
+
|
11
|
+
player = @game.turn
|
12
|
+
opponent = @game.opponent
|
13
|
+
|
14
|
+
loop do
|
15
|
+
|
16
|
+
@board.display
|
17
|
+
|
18
|
+
# look for pieces that need promotion
|
19
|
+
promote = @board.piece_to_promote?
|
20
|
+
if promote
|
21
|
+
puts "Promote your piece, enter 'Queen', 'Knight', 'Bishop', or 'Rook'"
|
22
|
+
new_piece = Kernel.const_get(gets.chomp.to_sym)
|
23
|
+
@board.promote(promote.location, new_piece)
|
24
|
+
end
|
25
|
+
|
26
|
+
# look for check and checkmate conditions
|
27
|
+
if player.king(@board).checkmate?(@board)
|
28
|
+
puts "#{player.color.capitalize} Player, you are in " + "CHECKMATE".colorize(:red)
|
29
|
+
puts "#{opponent.color.capitalize} Player " + "WINS".colorize(:green)
|
30
|
+
break
|
31
|
+
elsif player.king(@board).stalemate?(@board)
|
32
|
+
puts "#{player.color.capitalize} Player, you are in " + "STALEMATE".colorize(:yellow)
|
33
|
+
puts "DRAW"
|
34
|
+
break
|
35
|
+
elsif player.king(@board).check?(@board)
|
36
|
+
puts "#{player.color.capitalize} Player, you are in " + "CHECK".colorize(:yellow)
|
37
|
+
end
|
38
|
+
|
39
|
+
puts "#{player.color.capitalize} Player, enter your move:"
|
40
|
+
locs = gets.chomp.split(" ")
|
41
|
+
|
42
|
+
# handle special cases, otherwise run the move
|
43
|
+
case locs[0]
|
44
|
+
when "exit", "quit"
|
45
|
+
puts "Are you sure? (y/n)"
|
46
|
+
y_or_n = gets.chomp
|
47
|
+
break if y_or_n[0].upcase == "Y"
|
48
|
+
when "save"
|
49
|
+
puts "enter a name to save the game as:"
|
50
|
+
file_name = gets.chomp
|
51
|
+
@game.save("save/#{file_name}")
|
52
|
+
break
|
53
|
+
when "load"
|
54
|
+
puts "enter the name of the game you want to load:"
|
55
|
+
file_name = gets.chomp
|
56
|
+
@game = Game.load("save/#{file_name}")
|
57
|
+
@board = @game.board
|
58
|
+
players = [@game.white_player, @game.black_player]
|
59
|
+
player, opponent = @game.turn, @game.opponent
|
60
|
+
else
|
61
|
+
unless player.move(locs[0], locs[1], @board).nil?
|
62
|
+
player, opponent = opponent, player
|
63
|
+
@game.turn = player
|
64
|
+
@game.opponent = opponent
|
65
|
+
else
|
66
|
+
puts "Invalid move, try again".colorize(:red)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
data/save/test
ADDED
Binary file
|
data/spec/bishop_spec.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require_relative '../lib/chess/bishop.rb'
|
3
|
+
|
4
|
+
describe Bishop do
|
5
|
+
|
6
|
+
it { should be_a_kind_of(Piece) }
|
7
|
+
it { should respond_to :color }
|
8
|
+
it { should respond_to :location }
|
9
|
+
|
10
|
+
it "should know what its character is" do
|
11
|
+
@bishop = Bishop.new("White", "A1")
|
12
|
+
expect(@bishop.icon).to eq("\u2657")
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "valid moves" do
|
16
|
+
before { @bishop = Bishop.new("white", "D4") }
|
17
|
+
before { @board = Board.new }
|
18
|
+
|
19
|
+
it "should not be able to move vertically to any position" do
|
20
|
+
expect(@bishop.valid_move?("A3", @board)).to be_falsey
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should not be able to move horizontally to any position" do
|
24
|
+
expect(@bishop.valid_move?("D8", @board)).to be_falsey
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should be able to move diagonally" do
|
28
|
+
expect(@bishop.valid_move?("C3", @board)).to be_truthy
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|