Skip to content

Commit 5d1364b

Browse files
author
richelbilderbeek
committed
Can detect if a pawn just moved two squares
1 parent 3f53447 commit 5d1364b

File tree

10 files changed

+200
-3
lines changed

10 files changed

+200
-3
lines changed

action_history.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,22 @@ void action_history::add_action(const delta_t& t, const piece_action& action) no
2626
m_timed_actions.push_back(std::make_pair(t, action));
2727
}
2828

29+
std::vector<piece_action> collect_actions_in_timespan(
30+
const action_history& history,
31+
const delta_t from,
32+
const delta_t to
33+
)
34+
{
35+
assert(from < to);
36+
std::vector<piece_action> actions;
37+
for (const auto& p: history.get_timed_actions())
38+
{
39+
const delta_t& t{p.first};
40+
if (t >= from && t <= to) actions.push_back(p.second);
41+
}
42+
return actions;
43+
}
44+
2945
const piece_action& get_last_action(const action_history& history)
3046
{
3147
assert(has_actions(history));
@@ -37,6 +53,28 @@ bool has_actions(const action_history& history) noexcept
3753
return !history.get_timed_actions().empty();
3854
}
3955

56+
bool has_just_double_moved(
57+
const action_history& history,
58+
const delta_t when
59+
)
60+
{
61+
// It takes 1 time unit to do a move
62+
const delta_t start_earliest{when - delta_t(2.0)};
63+
const delta_t start_latest{when - delta_t(1.0)};
64+
const std::vector<piece_action> actions{
65+
collect_actions_in_timespan(
66+
history,
67+
start_earliest,
68+
start_latest
69+
)
70+
};
71+
for (const piece_action a: actions)
72+
{
73+
if (is_double_move(a)) return true;
74+
}
75+
return false;
76+
}
77+
4078
action_history merge_action_histories(const std::vector<action_history> histories)
4179
{
4280
std::vector<std::pair<delta_t, piece_action>> timed_actions;

action_history.h

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,36 @@ class action_history
1414
const std::vector<std::pair<delta_t, piece_action>>& timed_actions = {}
1515
);
1616

17+
/// Add an action, when started
1718
void add_action(const delta_t& t, const piece_action& action) noexcept;
1819

1920
const auto& get_timed_actions() const noexcept { return m_timed_actions; }
2021

2122
private:
2223

23-
/// The history of actions, in chrononical order
24+
/// The history of actions (i.e when they started), in chrononical order
2425
std::vector<std::pair<delta_t, piece_action>> m_timed_actions;
2526

2627
};
2728

29+
/// Collect all the actions that started in the timespan
30+
std::vector<piece_action> collect_actions_in_timespan(
31+
const action_history& history,
32+
const delta_t from,
33+
const delta_t to
34+
);
35+
36+
/// Has this piece (i.e. a pawn) just finish a double move forward last time unit?
37+
/// Only pawns can do this, e.g. e2-e4 or e7-e5
38+
/// For example, when at t=0.5, e2-e4 is played,
39+
/// from t=1.5 to t=2.5 this function will return true.
40+
/// Before that, the piece was moving
41+
/// After that, it was too long ago for en-passant
42+
bool has_just_double_moved(
43+
const action_history& action_history,
44+
const delta_t when
45+
);
46+
2847
const piece_action& get_last_action(const action_history& history);
2948

3049
bool has_actions(const action_history& history) noexcept;

delta_t.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,11 @@ bool operator<(const delta_t& lhs, const delta_t& rhs) noexcept
100100
return lhs.get() < rhs.get();
101101
}
102102

103+
bool operator<=(const delta_t& lhs, const delta_t& rhs) noexcept
104+
{
105+
return lhs.get() <= rhs.get();
106+
}
107+
103108
delta_t& operator+=(delta_t& lhs, const delta_t& rhs) noexcept
104109
{
105110
lhs = lhs + rhs;

delta_t.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ void test_delta_t();
2525

2626
bool operator==(const delta_t& lhs, const delta_t& rhs) noexcept;
2727
bool operator<(const delta_t& lhs, const delta_t& rhs) noexcept;
28+
bool operator<=(const delta_t& lhs, const delta_t& rhs) noexcept;
2829
delta_t& operator+=(delta_t& lhs, const delta_t& rhs) noexcept;
2930
delta_t operator+(const delta_t& lhs, const delta_t& rhs) noexcept;
3031
delta_t operator-(const delta_t& lhs, const delta_t& rhs) noexcept;

game.cpp

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,14 @@ std::vector<piece_action> collect_all_pawn_actions(
387387
assert(type == piece_type::pawn);
388388
const auto move_actions{collect_all_pawn_move_actions(g, p)};
389389
const auto attack_actions{collect_all_pawn_attack_actions(g, p)};
390-
return concatenate(move_actions, attack_actions);
390+
const auto en_passant_actions{collect_all_pawn_en_passant_actions(g, p)};
391+
return concatenate(
392+
concatenate(
393+
move_actions,
394+
attack_actions
395+
),
396+
en_passant_actions
397+
);
391398
}
392399

393400
std::vector<piece_action> collect_all_pawn_attack_actions(
@@ -456,6 +463,81 @@ std::vector<piece_action> collect_all_pawn_attack_actions(
456463
return actions;
457464
}
458465

466+
std::vector<piece_action> collect_all_pawn_en_passant_actions(
467+
const game& g,
468+
const piece& p
469+
)
470+
{
471+
std::vector<piece_action> actions;
472+
const auto type{p.get_type()};
473+
assert(type == piece_type::pawn);
474+
const auto& s{p.get_current_square()};
475+
const auto x{s.get_x()};
476+
const auto y{s.get_y()};
477+
const auto color{p.get_color()};
478+
const auto& from{p.get_current_square()};
479+
const auto enemy_color{get_other_color(color)};
480+
if (color == chess_color::black)
481+
{
482+
if (x != 3) return {};
483+
{
484+
if (y > 0)
485+
{
486+
const square to_square{square(x - 1, y - 1)};
487+
const square enemy_square{square(x, y - 1)};
488+
if (is_empty(g, to_square)
489+
&& is_piece_at(g, enemy_square)
490+
&& get_piece_at(g, enemy_square).get_color() == enemy_color
491+
&& has_just_double_moved(get_piece_at(g, enemy_square), g.get_time())
492+
)
493+
{
494+
actions.push_back(piece_action(color, type, piece_action_type::en_passant, from, to_square));
495+
}
496+
}
497+
if (y < 7)
498+
{
499+
const square to_square{square(x - 1, y + 1)};
500+
const square enemy_square{square(x, y + 1)};
501+
if (is_empty(g, to_square)
502+
&& is_piece_at(g, enemy_square)
503+
&& get_piece_at(g, enemy_square).get_color() == enemy_color
504+
&& has_just_double_moved(get_piece_at(g, enemy_square), g.get_time())
505+
)
506+
{
507+
actions.push_back(piece_action(color, type, piece_action_type::en_passant, from, to_square));
508+
}
509+
}
510+
}
511+
}
512+
else
513+
{
514+
assert(color == chess_color::white);
515+
assert(get_rank(s) != 1);
516+
// Attack
517+
if (x != 7)
518+
{
519+
if (y > 0)
520+
{
521+
const square enemy_square{square(x + 1, y - 1)};
522+
if (is_piece_at(g, enemy_square) && get_piece_at(g, enemy_square).get_color() == enemy_color)
523+
{
524+
actions.push_back(piece_action(color, type, piece_action_type::attack, from, enemy_square));
525+
}
526+
}
527+
if (y < 7)
528+
{
529+
const square enemy_square{square(x + 1, y + 1)};
530+
if (is_piece_at(g, enemy_square) && get_piece_at(g, enemy_square).get_color() == enemy_color)
531+
{
532+
actions.push_back(piece_action(color, type, piece_action_type::attack, from, enemy_square));
533+
}
534+
}
535+
}
536+
}
537+
return actions;
538+
}
539+
540+
459541
std::vector<piece_action> collect_all_pawn_move_actions(
460542
const game& g,
461543
const piece& p

game.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,13 @@ std::vector<piece_action> collect_all_pawn_attack_actions(
165165
const piece& p
166166
);
167167

168+
/// Collect all valid attack actions at a board
169+
/// for a focal pawn
170+
std::vector<piece_action> collect_all_pawn_en_passant_actions(
171+
const game& g,
172+
const piece& p
173+
);
174+
168175
/// Collect all valid move actions at a board
169176
/// for a focal pawn
170177
std::vector<piece_action> collect_all_pawn_move_actions(

piece.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,14 @@ bool has_actions(const piece& p) noexcept
305305
return count_piece_actions(p) != 0;
306306
}
307307

308+
bool has_just_double_moved(
309+
const piece& p,
310+
const delta_t when
311+
) noexcept
312+
{
313+
return has_just_double_moved(p.get_action_history(), when);
314+
}
315+
308316
bool has_moved(const piece& p) noexcept
309317
{
310318
return p.has_moved();
@@ -661,6 +669,25 @@ void test_piece()
661669
const auto p{get_test_white_king()};
662670
assert(!has_actions(p));
663671
}
672+
// has_just_double_moved
673+
{
674+
action_history h;
675+
assert(!has_just_double_moved(h, delta_t(2.0)));
676+
h.add_action(
677+
delta_t(0.5),
678+
piece_action(
679+
chess_color::white,
680+
piece_type::pawn,
681+
piece_action_type::move,
682+
"e2",
683+
"e4"
684+
)
685+
);
686+
assert(!has_just_double_moved(h, delta_t(0.0)));
687+
assert(!has_just_double_moved(h, delta_t(1.0)));
688+
assert(has_just_double_moved(h, delta_t(2.0)));
689+
assert(!has_just_double_moved(h, delta_t(3.0)));
690+
}
664691
// is_idle
665692
{
666693
const auto p{get_test_white_king()};

piece.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,9 +218,17 @@ piece get_test_white_knight() noexcept;
218218
/// Does the piece have actions to do?
219219
bool has_actions(const piece& p) noexcept;
220220

221+
/// Has this piece (i.e. a pawn) did a double move forward last time unit?
222+
/// Only pawns can do this, e.g. e2-e4 or e7-e5
223+
bool has_just_double_moved(
224+
const piece& p,
225+
const delta_t when
226+
) noexcept;
227+
221228
/// Has this piece (attempted to) move?
222229
bool has_moved(const piece& p) noexcept;
223230

231+
224232
/// Is the unit dead?
225233
bool is_dead(const piece& p) noexcept;
226234

piece_action.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,13 @@ piece_action get_test_piece_action() noexcept
4949
);
5050
}
5151

52+
bool is_double_move(const piece_action& a) noexcept
53+
{
54+
return a.get_piece_type() == piece_type::pawn
55+
&& a.get_action_type() == piece_action_type::move
56+
&& std::abs(a.get_from().get_x() - a.get_to().get_x()) == 2;
57+
}
58+
5259
bool is_atomic(const piece_action& a) noexcept
5360
{
5461
if (a.get_from() == a.get_to()) return true;

piece_action.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,13 @@ std::string describe_action(const piece_action& p);
5656
/// Get a piece_action to be used in testing
5757
piece_action get_test_piece_action() noexcept;
5858

59+
/// Is this a pawn moving two squares forward?
60+
bool is_double_move(const piece_action& a) noexcept;
61+
5962
/// Is the action atomic, i.e. it cannot be split up further.
6063
/// For example, moving a queen d1 to d3 is not atomic,
6164
/// as it is split up in d1 -> d2 -> d3
62-
bool is2_atomic(const piece_action& a) noexcept;
65+
bool is_atomic(const piece_action& a) noexcept;
6366

6467
/// Test the 'piece_action' class and its free functions
6568
void test_piece_action();

0 commit comments

Comments
 (0)