Skip to content

Commit 7133de3

Browse files
author
richelbilderbeek
committed
Progress with castling, progress #3
1 parent 5313ddc commit 7133de3

13 files changed

+256
-33
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ See [FAQ](FAQ.md)
2222

2323
## Screenshots
2424

25+
![](screenshots/20220808_1.png)
26+
2527
![](screenshots/20220807_1.png)
2628

2729
![](screenshots/20220804_1.png)

game.cpp

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,53 @@ void game::add_action(const control_action a)
3333
m_control_actions.add(a);
3434
}
3535

36+
bool can_castle_kingside(const piece& p, const game& g) noexcept
37+
{
38+
assert(p.get_type() == piece_type::king);
39+
if (has_moved(p)) return false;
40+
const auto king_square{p.get_current_square()};
41+
// In a starting position, it may be that king has not made a new move
42+
if (king_square != square("e1") && king_square == square("e8")) return false;
43+
const auto rook_square(square(king_square.get_x(), 0));
44+
if (!is_piece_at(g, rook_square)) return false;
45+
const auto rook{get_piece_at(g, rook_square)};
46+
if (rook.get_type() != piece_type::rook) return false;
47+
if (has_moved(rook)) return false;
48+
const auto b_pawn_square(square(king_square.get_x(), 1));
49+
if (!is_empty(g, b_pawn_square)) return false;
50+
const chess_color enemy_color{get_other_color(p.get_color())};
51+
if (is_square_attacked_by(g, b_pawn_square, enemy_color)) return false;
52+
const auto c_pawn_square(square(king_square.get_x(), 2));
53+
if (!is_empty(g, c_pawn_square)) return false;
54+
if (is_square_attacked_by(g, c_pawn_square, enemy_color)) return false;
55+
const auto d_pawn_square(square(king_square.get_x(), 3));
56+
if (!is_empty(g, d_pawn_square)) return false;
57+
if (is_square_attacked_by(g, d_pawn_square, enemy_color)) return false;
58+
return true;
59+
}
60+
61+
bool can_castle_queenside(const piece& p, const game& g) noexcept
62+
{
63+
assert(p.get_type() == piece_type::king);
64+
if (has_moved(p)) return false;
65+
const auto king_square{p.get_current_square()};
66+
// In a starting position, it may be that king has not made a new move
67+
if (king_square != square("e1") && king_square == square("e8")) return false;
68+
const auto rook_square(square(king_square.get_x(), 7));
69+
if (!is_piece_at(g, rook_square)) return false;
70+
const auto rook{get_piece_at(g, rook_square)};
71+
if (rook.get_type() != piece_type::rook) return false;
72+
if (has_moved(rook)) return false;
73+
const auto f_pawn_square(square(king_square.get_x(), 1));
74+
if (!is_empty(g, f_pawn_square)) return false;
75+
const chess_color enemy_color{get_other_color(p.get_color())};
76+
if (is_square_attacked_by(g, f_pawn_square, enemy_color)) return false;
77+
const auto g_pawn_square(square(king_square.get_x(), 2));
78+
if (!is_empty(g, g_pawn_square)) return false;
79+
if (is_square_attacked_by(g, g_pawn_square, enemy_color)) return false;
80+
return true;
81+
}
82+
3683
bool can_player_select_piece_at_cursor_pos(
3784
const game& g,
3885
const chess_color player
@@ -75,6 +122,26 @@ std::vector<piece_action> collect_all_actions(const game& g)
75122
return actions;
76123
}
77124

125+
std::vector<piece_action> collect_all_actions(
126+
const game& g,
127+
const chess_color player_color)
128+
{
129+
std::vector<piece_action> actions;
130+
for (const auto& p: g.get_pieces())
131+
{
132+
if (p.get_color() != player_color) continue;
133+
const auto piece_actions{
134+
collect_all_actions(g, p)
135+
};
136+
std::copy(
137+
std::begin(piece_actions),
138+
std::end(piece_actions),
139+
std::back_inserter(actions)
140+
);
141+
}
142+
return actions;
143+
}
144+
78145
std::vector<piece_action> collect_all_actions(
79146
const game& g,
80147
const piece& p
@@ -182,6 +249,30 @@ std::vector<piece_action> collect_all_king_actions(
182249
}
183250
}
184251
}
252+
if (can_castle_kingside(p, g))
253+
{
254+
const square to{
255+
p.get_current_square().get_x(),
256+
p.get_current_square().get_y() + 2,
257+
};
258+
actions.push_back(
259+
piece_action(
260+
color, type, piece_action_type::castle_kingside, from, to
261+
)
262+
);
263+
}
264+
if (can_castle_queenside(p, g))
265+
{
266+
const square to{
267+
p.get_current_square().get_x(),
268+
p.get_current_square().get_y() - 2,
269+
};
270+
actions.push_back(
271+
piece_action(
272+
color, type, piece_action_type::castle_queenside, from, to
273+
)
274+
);
275+
}
185276
return actions;
186277
}
187278

@@ -912,6 +1003,24 @@ bool is_piece_at(
9121003
return is_piece_at(g.get_pieces(), coordinat);
9131004
}
9141005

1006+
bool is_square_attacked_by(
1007+
const game& g,
1008+
const square& s,
1009+
const chess_color enemy_color
1010+
)
1011+
{
1012+
// Need the enemy_color, else 'collect_all_actions' results in infinite recursion
1013+
for (const auto& action: collect_all_actions(g, enemy_color))
1014+
{
1015+
1016+
if (action.get_action_type() == piece_action_type::move
1017+
&& action.get_to() == s
1018+
&& action.get_color() == enemy_color
1019+
) return true;
1020+
}
1021+
return false;
1022+
}
1023+
9151024
bool piece_with_id_is_at(
9161025
game& g,
9171026
const id& i,

game.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,12 @@ class game
9292
friend void test_game();
9393
};
9494

95+
/// Can this piece castle kingside?
96+
bool can_castle_kingside(const piece& p, const game& g) noexcept;
97+
98+
/// Can this piece castle queenside?
99+
bool can_castle_queenside(const piece& p, const game& g) noexcept;
100+
95101
/// Can the player select a piece at the current mouse position?
96102
bool can_player_select_piece_at_cursor_pos(
97103
const game& g,
@@ -106,6 +112,13 @@ void clear_piece_messages(game& g) noexcept;
106112
/// for all pieces
107113
std::vector<piece_action> collect_all_actions(const game& g);
108114

115+
/// Collect all valid moves and attackes at a board
116+
/// for all pieces of a certain color
117+
std::vector<piece_action> collect_all_actions(
118+
const game& g,
119+
const chess_color player_color
120+
);
121+
109122
/// Collect all valid moves and attackes at a board
110123
/// for a focal piece
111124
std::vector<piece_action> collect_all_actions(
@@ -395,6 +408,13 @@ bool is_piece_at(
395408
const square& coordinat
396409
);
397410

411+
/// Is the square attacked by a certain (enemy) color?
412+
bool is_square_attacked_by(
413+
const game& g,
414+
const square& s,
415+
const chess_color enemy_color
416+
);
417+
398418
/// See if there is a piece with a certain ID at a certain square
399419
bool piece_with_id_is_at(
400420
game& g,

piece.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ piece::piece(
2020
: m_color{color},
2121
m_current_action_time{delta_t(0.0)},
2222
m_current_square{coordinat},
23+
m_has_moved{false},
2324
m_health{::get_max_health(type)},
2425
m_id{create_new_id()},
2526
m_is_selected{false},
@@ -292,6 +293,10 @@ bool has_actions(const piece& p) noexcept
292293
return count_piece_actions(p) != 0;
293294
}
294295

296+
bool has_moved(const piece& p) noexcept
297+
{
298+
return p.has_moved();
299+
}
295300

296301
bool is_dead(const piece& p) noexcept
297302
{
@@ -381,6 +386,27 @@ void test_piece()
381386
const auto piece{get_test_white_knight()};
382387
assert(piece.get_kill_count() == 0);
383388
}
389+
// piece::has_moved
390+
{
391+
// a piece has not moved at the start
392+
{
393+
const auto piece{get_test_white_knight()};
394+
assert(!piece.has_moved());
395+
}
396+
// a piece has moved after a movement
397+
{
398+
piece p(
399+
chess_color::white,
400+
piece_type::pawn,
401+
square("e2")
402+
);
403+
assert(!p.has_moved());
404+
p.add_action(piece_action(chess_color::white, piece_type::pawn, piece_action_type::move, square("e2"), square("e4")));
405+
game g;
406+
p.tick(delta_t(0.01), g);
407+
assert(p.has_moved());
408+
}
409+
}
384410
// piece::get_messages
385411
{
386412
auto piece{get_test_white_knight()};
@@ -815,6 +841,7 @@ void piece::tick(
815841
switch(action_type)
816842
{
817843
case piece_action_type::move:
844+
m_has_moved = true; // Whatever happens, this piece has tried to move
818845
return tick_move(*this, dt, g);
819846
case piece_action_type::attack:
820847
return tick_attack(*this, dt, g);

piece.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ class piece
6969
/// Get the type of piece, e.g. king, queen, rook, bishop, knight, pawn
7070
piece_type get_type() const noexcept { return m_type; }
7171

72+
/// Has this piece (attempted to) moved?
73+
bool has_moved() const noexcept { return m_has_moved; }
74+
7275
/// Increase the kill count by one
7376
void increase_kill_count() noexcept { ++m_kill_count; }
7477

@@ -114,6 +117,9 @@ class piece
114117
/// The square the piece occupies now
115118
square m_current_square;
116119

120+
/// Has this piece (attempted to) move?
121+
bool m_has_moved;
122+
117123
/// The health
118124
double m_health;
119125

@@ -200,6 +206,9 @@ piece get_test_white_knight() noexcept;
200206
/// Does the piece have actions to do?
201207
bool has_actions(const piece& p) noexcept;
202208

209+
/// Has this piece (attempted to) move?
210+
bool has_moved(const piece& p) noexcept;
211+
203212
/// Is the unit dead?
204213
bool is_dead(const piece& p) noexcept;
205214

piece_action_type.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ enum class piece_action_type
88
{
99
move,
1010
attack,
11-
promote
11+
promote,
12+
castle_kingside,
13+
castle_queenside
1214
};
1315

1416
/// Convert to string

pieces.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,36 @@ std::vector<piece> get_pieces_queen_endgame() noexcept
612612
};
613613
}
614614

615+
std::vector<piece> get_pieces_ready_to_castle() noexcept
616+
{
617+
return
618+
{
619+
piece(chess_color::white, piece_type::rook, square("a1")),
620+
piece(chess_color::white, piece_type::king, square("e1")),
621+
piece(chess_color::white, piece_type::rook, square("h1")),
622+
piece(chess_color::white, piece_type::pawn, square("a2")),
623+
piece(chess_color::white, piece_type::pawn, square("b2")),
624+
piece(chess_color::white, piece_type::pawn, square("c2")),
625+
piece(chess_color::white, piece_type::pawn, square("d2")),
626+
piece(chess_color::white, piece_type::pawn, square("e2")),
627+
piece(chess_color::white, piece_type::pawn, square("f2")),
628+
piece(chess_color::white, piece_type::pawn, square("g2")),
629+
piece(chess_color::white, piece_type::pawn, square("h2")),
630+
piece(chess_color::black, piece_type::rook, square("a8")),
631+
piece(chess_color::black, piece_type::king, square("e8")),
632+
piece(chess_color::black, piece_type::rook, square("h8")),
633+
piece(chess_color::black, piece_type::pawn, square("a7")),
634+
piece(chess_color::black, piece_type::pawn, square("b7")),
635+
piece(chess_color::black, piece_type::pawn, square("c7")),
636+
piece(chess_color::black, piece_type::pawn, square("d7")),
637+
piece(chess_color::black, piece_type::pawn, square("e7")),
638+
piece(chess_color::black, piece_type::pawn, square("f7")),
639+
piece(chess_color::black, piece_type::pawn, square("g7")),
640+
piece(chess_color::black, piece_type::pawn, square("h7"))
641+
};
642+
}
643+
644+
615645
std::vector<piece> get_standard_starting_pieces() noexcept
616646
{
617647
return
@@ -671,6 +701,8 @@ std::vector<piece> get_starting_pieces(const starting_position_type t) noexcept
671701
return get_pieces_pawns_near_promotion();
672702
case starting_position_type::queen_end_game:
673703
return get_pieces_queen_endgame();
704+
case starting_position_type::ready_to_castle:
705+
return get_pieces_ready_to_castle();
674706
case starting_position_type::standard:
675707
default:
676708
assert(t == starting_position_type::standard);

pieces.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,9 @@ std::vector<piece> get_pieces_pawns_near_promotion() noexcept;
162162
/// from a default setup
163163
std::vector<piece> get_pieces_queen_endgame() noexcept;
164164

165+
/// Get the pieces for a kings that are ready to castle
166+
std::vector<piece> get_pieces_ready_to_castle() noexcept;
167+
165168
/// Get all the pieces in the starting position type
166169
std::vector<piece> get_starting_pieces(
167170
const starting_position_type t

screenshots/20220808_1.png

694 KB
Loading

sfml_helper.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -227,15 +227,21 @@ sf::Color to_sfml_color(
227227
{
228228
return sf::Color(255 - 64, 255 - 0, 255 - 64);
229229
}
230-
assert(t == piece_action_type::attack);
230+
assert(t == piece_action_type::attack
231+
|| t == piece_action_type::castle_kingside
232+
|| t == piece_action_type::castle_queenside
233+
);
231234
return sf::Color(255 - 0, 255 - 64, 255 - 64);
232235
}
233236
assert(color == chess_color::black);
234237
if (t == piece_action_type::move || t == piece_action_type::promote)
235238
{
236239
return sf::Color(128 - 64, 128 - 0, 128 - 64);
237240
}
238-
assert(t == piece_action_type::attack);
241+
assert(t == piece_action_type::attack
242+
|| t == piece_action_type::castle_kingside
243+
|| t == piece_action_type::castle_queenside
244+
);
239245
return sf::Color(128 - 0, 128 - 64, 128 - 64);
240246
}
241247

0 commit comments

Comments
 (0)