bchess 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,21 @@
1
+ module Bchess
2
+ class Game
3
+ attr_reader :fen, :board, :moves
4
+
5
+ def initialize(fen='')
6
+ @fen = fen
7
+ @board = Board.new(fen)
8
+ @moves = []
9
+ end
10
+
11
+ def add_move(move)
12
+ moves << move
13
+ end
14
+
15
+ def validate_game
16
+ moves.all? do |move|
17
+ board.execute(move)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,43 @@
1
+ module Bchess
2
+ module BoardHelpers
3
+ def field(column, row)
4
+ (column+97).chr + (row+1).to_s
5
+ end
6
+
7
+ def invalid_data?(piece, column, row)
8
+ piece.nil? || !(0..7).include?(column) || !(0..7).include?(row)
9
+ end
10
+
11
+ def castle_detected?(piece, column)
12
+ piece.kind_of?(Bchess::King) && piece.column == 4 && (column - piece.column).abs == 2
13
+ end
14
+
15
+ def promotion_detected?(piece, row)
16
+ piece.kind_of?(Bchess::Pawn) && (row == 0 || row == 7)
17
+ end
18
+
19
+ def en_passant_detected?(piece, column, row)
20
+ piece.kind_of?(Bchess::Pawn) && piece.row != row && piece.column != column && at(column, row).nil? && piece.can_take_on_field?(column, row)
21
+ end
22
+
23
+ def pawn_long_move_detected?(piece, row)
24
+ piece.kind_of?(Bchess::Pawn) && (piece.row - row).abs == 2
25
+ end
26
+
27
+ def kings_present?
28
+ !!king(Bchess::WHITE) && !!king(Bchess::BLACK)
29
+ end
30
+
31
+ def to_row(row)
32
+ row.to_i - 1
33
+ end
34
+
35
+ def to_column(column)
36
+ column.bytes.first - 97
37
+ end
38
+
39
+ def field(column, row)
40
+ (column+97).chr + (row+1).to_s
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,58 @@
1
+ module CastleHelpers
2
+ def castle(piece, column, row)
3
+ validate_castle(piece, column)
4
+ update_castles_after_king_move(piece.color)
5
+ execute_castle(piece, column, row)
6
+ end
7
+
8
+ def validate_castle(piece, column)
9
+ !piece.moved && !rook_moved?(piece, column) && fen_allows?(piece,column)
10
+ end
11
+
12
+ def execute_castle(piece, column, row)
13
+ piece.move(column, row)
14
+ lngth = @short_castle ? 2 : 3
15
+ @castling_rook = castling_rook(piece, column)
16
+ @castling_rook.move((@castling_rook.column - lngth).abs, row)
17
+ end
18
+
19
+ def white_castle(column)
20
+ if short_castle?(column)
21
+ @short_castle = true
22
+ at(7,0)
23
+ else
24
+ @short_castle = false
25
+ at(0,0)
26
+ end
27
+ end
28
+
29
+ def black_castle(column)
30
+ if short_castle?(column)
31
+ @short_castle = true
32
+ at(7,7)
33
+ else
34
+ @short_castle = false
35
+ at(0,7)
36
+ end
37
+ end
38
+
39
+ def rook_moved?(piece, column)
40
+ castling_rook(piece, column)&.moved
41
+ end
42
+
43
+ def castling_rook(piece, column)
44
+ select_rook(piece, column)
45
+ end
46
+
47
+ def select_rook(piece, column)
48
+ if piece.row == 0
49
+ white_castle(column)
50
+ elsif piece.row == 7
51
+ black_castle(column)
52
+ end
53
+ end
54
+
55
+ def short_castle?(column)
56
+ column == 6
57
+ end
58
+ end
@@ -0,0 +1,22 @@
1
+ module EnPassantHelpers
2
+ def validate_en_passant(piece, column, row)
3
+ #TODO
4
+ true
5
+ end
6
+
7
+ def execute_en_passant(piece, row, column)
8
+ piece.move(row, column)
9
+ remove_old_piece(*remove_en_passant(piece, *transform_field(@en_passant)), piece.color)
10
+ end
11
+
12
+ def remove_en_passant(piece, column, row)
13
+ direction = piece.color == Bchess::WHITE ? 1 : -1
14
+ [column, row - direction]
15
+ end
16
+
17
+ def long_pawn_move(piece, column, row)
18
+ piece.move(column, row)
19
+ direction = piece.color == Bchess::WHITE ? 1 : -1
20
+ @en_passant = field(column, (row + piece.row)/2 - direction)
21
+ end
22
+ end
@@ -0,0 +1,141 @@
1
+ module Bchess
2
+ module FenHelpers
3
+ def fen_hash
4
+ {
5
+ 'k': {klass: Bchess::King, color: Bchess::BLACK},
6
+ 'q': {klass: Bchess::Queen, color: Bchess::BLACK},
7
+ 'r': {klass: Bchess::Rook, color: Bchess::BLACK},
8
+ 'b': {klass: Bchess::Bishop, color: Bchess::BLACK},
9
+ 'n': {klass: Bchess::Knight, color: Bchess::BLACK},
10
+ 'p': {klass: Bchess::Pawn, color: Bchess::BLACK},
11
+ 'K': {klass: Bchess::King, color: Bchess::WHITE},
12
+ 'Q': {klass: Bchess::Queen, color: Bchess::WHITE},
13
+ 'R': {klass: Bchess::Rook, color: Bchess::WHITE},
14
+ 'B': {klass: Bchess::Bishop, color: Bchess::WHITE},
15
+ 'N': {klass: Bchess::Knight, color: Bchess::WHITE},
16
+ 'P': {klass: Bchess::Pawn, color: Bchess::WHITE},
17
+ }
18
+ end
19
+
20
+ def write_fen
21
+ result = ''
22
+ 7.downto(0) do |i|
23
+ line_pieces = pieces.select{ |p| p.row == i }
24
+ one_line = create_fen_line(line_pieces)
25
+ result << one_line
26
+ result << '/' unless i == 0
27
+ end
28
+ result.concat(additional_info)
29
+ end
30
+
31
+ def create_fen_line(pieces)
32
+ line = ''
33
+ counter = 0
34
+
35
+ 0.upto(7) do |i|
36
+ piece = pieces.select{ |p| p.column == i }.first
37
+ if !!piece
38
+ if counter > 0
39
+ line.concat(counter.to_s)
40
+ counter = 0
41
+ line.concat(to_fen(piece))
42
+ else
43
+ line.concat(to_fen(piece))
44
+ end
45
+ else
46
+ counter += 1
47
+ end
48
+ end
49
+ line.concat(counter.to_s) if counter > 0
50
+ line
51
+ end
52
+
53
+ def set_pieces(board)
54
+ pieces.clear
55
+ board.split("/").each_with_index do |line, index|
56
+ column = 0
57
+ line.each_char do |char|
58
+ if char.to_i != 0
59
+ column += char.to_i - 1
60
+ else
61
+ pieces << fen_hash[char.to_sym][:klass].new(fen_hash[char.to_sym][:color], column, 7-index)
62
+ end
63
+ column += 1
64
+ end
65
+ end
66
+ end
67
+
68
+ def fen_allows?(piece, column)
69
+ if piece.color == Bchess::WHITE
70
+ if column == 6
71
+ castles.chars.include?('k')
72
+ else
73
+ castles.chars.include?('q')
74
+ end
75
+ else
76
+ if column == 6
77
+ castles.chars.include?('K')
78
+ else
79
+ castles.chars.include?('Q')
80
+ end
81
+ end
82
+ end
83
+
84
+ def to_fen(piece)
85
+ fen_hash.key({ :klass => piece.class, :color => piece.color }).to_s
86
+ end
87
+
88
+ def change_halfmove_clock(piece)
89
+ if piece.kind_of?(Bchess::Pawn)
90
+ @halfmove_clock = 0
91
+ else
92
+ @halfmove_clock = halfmove_clock + 1
93
+ end
94
+ end
95
+
96
+ def update_castles_after_move(piece)
97
+ if piece == Bchess::King
98
+ update_castles_after_king_move(piece.color)
99
+ elsif piece == Bchess::Rook
100
+ update_castles_after_rook_move(piece)
101
+ end
102
+ @castles = '-' if @castles == ''
103
+ end
104
+
105
+ def update_castles_after_king_move(color)
106
+ if color == Bchess::WHITE
107
+ @castles.gsub!('K', '').gsub!('Q', '')
108
+ else
109
+ @castles.gsub!('k', '').gsub!('q', '')
110
+ end
111
+ end
112
+
113
+ def change_move_number
114
+ @move_number = move_number + 1
115
+ end
116
+
117
+ def set_to_move(fen_colors)
118
+ @to_move = fen_colors == 'w' ? Bchess::WHITE : Bchess::BLACK
119
+ end
120
+
121
+ def set_castles(fen_castles)
122
+ @castles = fen_castles
123
+ end
124
+
125
+ def set_en_passant(fen_en_passant)
126
+ @en_passant = fen_en_passant
127
+ end
128
+
129
+ def set_halfmove_clock(fen_halfmove_clock)
130
+ @halfmove_clock = fen_halfmove_clock.to_i
131
+ end
132
+
133
+ def set_move_number(fen_move_number)
134
+ @move_number = fen_move_number.to_i
135
+ end
136
+
137
+ def additional_info
138
+ " #{to_move} #{castles} #{en_passant} #{halfmove_clock} #{move_number}"
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,50 @@
1
+ module FieldBetweenHelpers
2
+ def row_fields(dcolumn, drow)
3
+ smaller, bigger = [column, dcolumn].sort
4
+ (smaller+1..bigger-1).map{|c| [c, row] }
5
+ end
6
+
7
+ def column_fields(dcolumn, drow)
8
+ smaller, bigger = [row, drow].sort
9
+ (smaller+1..bigger-1).map{|r| [column, r] }
10
+ end
11
+
12
+ def diagonal_fields(dcolumn, drow)
13
+ fields = []
14
+ if dcolumn > column
15
+ if drow > row
16
+ (dcolumn - column - 1).times do |i|
17
+ fields << [dcolumn-(i+1), drow-(i+1)]
18
+ end
19
+ else
20
+ (dcolumn - column - 1).times do |i|
21
+ fields << [dcolumn-(i+1), drow+(i+1)]
22
+ end
23
+ end
24
+ else
25
+ if drow > row
26
+ (column - dcolumn - 1).times do |i|
27
+ fields << [dcolumn+(i+1), drow-(i+1)]
28
+ end
29
+ else
30
+ (column - dcolumn - 1).times do |i|
31
+ fields << [dcolumn+(i+1), drow+(i+1)]
32
+ end
33
+ end
34
+ end
35
+ fields
36
+ end
37
+
38
+ def fields_between(dcolumn, drow)
39
+ return [] unless can_move_to_field?(dcolumn, drow)
40
+ if same_row?(drow)
41
+ row_fields(dcolumn, drow)
42
+ elsif same_column?(dcolumn)
43
+ column_fields(dcolumn, drow)
44
+ elsif same_diagonal?(dcolumn, drow)
45
+ diagonal_fields(dcolumn, drow)
46
+ else
47
+ []
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,16 @@
1
+ module Validations
2
+ def validate_move
3
+ if !valid_position?
4
+ read_fen
5
+ false
6
+ else
7
+ @fen = write_fen
8
+ true
9
+ end
10
+ end
11
+
12
+ def valid_position?
13
+ kings_present? &&
14
+ !king_attacked(just_moved)
15
+ end
16
+ end
@@ -0,0 +1,30 @@
1
+ module Bchess
2
+ class King < Piece
3
+
4
+ KINGS_REACH = 1
5
+
6
+ attr_reader :moved
7
+
8
+ def initiialize(*args)
9
+ super(args)
10
+ @moved = false
11
+ end
12
+
13
+ def name
14
+ 'K'
15
+ end
16
+
17
+ def move(dcolumn, drow)
18
+ super(dcolumn, drow)
19
+ @moved = true
20
+ end
21
+
22
+ def can_move_to_field?(dcolumn, drow)
23
+ super &&
24
+ (
25
+ by_line(dcolumn, drow, KINGS_REACH) ||
26
+ by_diagonal(dcolumn, drow, KINGS_REACH)
27
+ )
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,27 @@
1
+ module Bchess
2
+ class Knight < Piece
3
+
4
+ def initiialize(*args)
5
+ super(args)
6
+ end
7
+
8
+ def name
9
+ 'N'
10
+ end
11
+
12
+ def can_move_to_field?(dcolumn, drow)
13
+ super && by_jump(dcolumn, drow)
14
+ end
15
+
16
+ def fields_between(column, row)
17
+ []
18
+ end
19
+
20
+ private
21
+
22
+ def by_jump(dcolumn, drow)
23
+ (row - drow).abs + (column - dcolumn).abs == 3 &&
24
+ (row - drow).abs != 3 && (column - dcolumn).abs != 3
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,54 @@
1
+ module Bchess
2
+ class Pawn < Piece
3
+
4
+ def initiialize(*args)
5
+ super(args)
6
+ end
7
+
8
+ def name
9
+ ''
10
+ end
11
+
12
+ def valid?
13
+ super && pawn_position?
14
+ end
15
+
16
+ def can_move_to_field?(dcolumn, drow)
17
+ super &&
18
+ pawn_move(dcolumn, drow)
19
+ end
20
+
21
+ def can_take_on_field?(dcolumn, drow)
22
+ direction = white? ? 1 : -1
23
+ by_diagonal(dcolumn, drow, 1) && (drow - row) == direction
24
+ end
25
+
26
+ private
27
+
28
+ def pawn_move(dcolumn, drow)
29
+ row_diff?(dcolumn, drow) &&
30
+ direction_kept?(dcolumn, drow) &&
31
+ column_kept?(dcolumn, column)
32
+ end
33
+
34
+ def column_kept?(dcolumn, column)
35
+ column == dcolumn
36
+ end
37
+
38
+ def direction_kept?(dcolumn, drow)
39
+ white? ? drow > row : row > drow
40
+ end
41
+
42
+ def row_diff?(dcolumn, drow)
43
+ (row - drow).abs <= (starting_position? ? 2 : 1)
44
+ end
45
+
46
+ def starting_position?
47
+ row == (white? ? 1 : 6)
48
+ end
49
+
50
+ def pawn_position?
51
+ (1..6).include?(row)
52
+ end
53
+ end
54
+ end