Skip to content

Commit

Permalink
Lasker Morris: Allow pieces to move before they have all been placed
Browse files Browse the repository at this point in the history
  • Loading branch information
calcitem committed Jun 6, 2024
1 parent dfaad15 commit e3a7b4b
Show file tree
Hide file tree
Showing 9 changed files with 51 additions and 13 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,7 @@ cov-int
flutter_export_environment.sh
.autogit
build/
out/

# Snapcraft
*.snap
1 change: 1 addition & 0 deletions src/mills.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,7 @@ bool is_star_squares_full(Position *pos)
return ret;
}

// TODO: For Lasker Morris
Depth get_search_depth(const Position *pos)
{
Depth d = 0;
Expand Down
10 changes: 9 additions & 1 deletion src/movegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,13 @@ ExtMove *generate<MOVE>(Position &pos, ExtMove *moveList)
template <>
ExtMove *generate<PLACE>(Position &pos, ExtMove *moveList)
{
const Color us = pos.side_to_move();
ExtMove *cur = moveList;

if (pos.piece_in_hand_count(us) == 0) {
return cur;
}

for (auto s : MoveList<LEGAL>::movePriorityList) {
if (!pos.get_board()[s]) {
*cur++ = static_cast<Move>(s);
Expand Down Expand Up @@ -129,11 +134,14 @@ ExtMove *generate<LEGAL>(Position &pos, ExtMove *moveList)
switch (pos.get_action()) {
case Action::select:
case Action::place:
// Generate both PLACE and MOVE actions if the phase is placing
if (pos.get_phase() == Phase::placing ||
pos.get_phase() == Phase::ready) {
return generate<PLACE>(pos, moveList);
cur = generate<PLACE>(pos, moveList);
return generate<MOVE>(pos, cur);
}

// Generate MOVE actions if the phase is moving
if (pos.get_phase() == Phase::moving) {
return generate<MOVE>(pos, moveList);
}
Expand Down
3 changes: 2 additions & 1 deletion src/movepick.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ void MovePicker::score()
to, pos.side_to_move(), from);

#ifndef SORT_MOVE_WITHOUT_HUMAN_KNOWLEDGE
// TODO(calcitem): rule.mayRemoveMultiple adapt other rules
// TODO(calcitem): rule.mayRemoveMultiple adapt other rules such as
// Lasker Morris
if (type_of(m) != MOVETYPE_REMOVE) {
// all phrase, check if place sq can close mill
if (ourMillsCount > 0) {
Expand Down
26 changes: 21 additions & 5 deletions src/position.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -690,8 +690,7 @@ bool Position::put_piece(Square s, bool updateRecord)
{
const Color us = sideToMove;

if (phase == Phase::gameOver || action != Action::place ||
!(SQ_BEGIN <= s && s < SQ_END) || board[s]) {
if (phase == Phase::gameOver || !(SQ_BEGIN <= s && s < SQ_END)) {
return false;
}

Expand All @@ -701,7 +700,17 @@ bool Position::put_piece(Square s, bool updateRecord)
start();
}

if (phase == Phase::placing) {
// Emanuel Lasker Morris: Allow moving pieces during the placing phase
if (phase == Phase::placing && can_move_during_placing_phase()) {
// Allow moving if the piece is already on the board
if (board[s] & make_piece(us)) {
currentSquare = s;
action = Action::place;
return true;
}
}

if (phase == Phase::placing && action == Action::place) {
const auto piece = static_cast<Piece>((0x01 | make_piece(sideToMove)) +
rule.pieceCount -
pieceInHandCount[us]);
Expand Down Expand Up @@ -995,7 +1004,9 @@ bool Position::remove_piece(Square s, bool updateRecord)

bool Position::select_piece(Square s)
{
if (phase != Phase::moving)
// Allow selecting pieces during placing phase if allowed
if (phase != Phase::moving &&
!(phase == Phase::placing && can_move_during_placing_phase()))
return false;

if (action != Action::select && action != Action::place)
Expand Down Expand Up @@ -1046,6 +1057,11 @@ bool Position::handle_placing_phase_end()
return true;
}

inline bool Position::can_move_during_placing_phase() const
{
return rule.mayMoveInPlacingPhase; // TODO: piece in hand
}

bool Position::resign(Color loser)
{
if (phase == Phase::ready || phase == Phase::gameOver ||
Expand Down Expand Up @@ -1257,7 +1273,7 @@ inline void Position::set_side_to_move(Color c)

them = ~sideToMove;

if (pieceInHandCount[sideToMove] == 0) {
if (pieceInHandCount[sideToMove] == 0 || can_move_during_placing_phase()) {
phase = Phase::moving;
action = Action::select;
} else {
Expand Down
2 changes: 2 additions & 0 deletions src/position.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,8 @@ class Position

bool handle_placing_phase_end();

bool can_move_during_placing_phase() const;

// Data members
Piece board[SQUARE_EXT_NB];
Bitboard byTypeBB[PIECE_TYPE_NB];
Expand Down
10 changes: 7 additions & 3 deletions src/search.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,9 @@ int Thread::search()
std::chrono::steady_clock::time_point cycleEnd;
#endif

if (rootPos->get_phase() == Phase::moving) {
if (rootPos->get_phase() == Phase::moving ||
(rootPos->get_phase() == Phase::placing &&
rule.mayMoveInPlacingPhase)) {
#ifdef RULE_50
if (posKeyHistory.size() >= rule.nMoveRule) {
return 50;
Expand All @@ -123,10 +125,12 @@ int Thread::search()
assert(posKeyHistory.size() < 256);
}

if (rootPos->get_phase() == Phase::placing) {
if (rootPos->get_phase() == Phase::placing && !rule.mayMoveInPlacingPhase) {
posKeyHistory.clear();
rootPos->st.rule50 = 0;
} else if (rootPos->get_phase() == Phase::moving) {
} else if (rootPos->get_phase() == Phase::moving ||
(rootPos->get_phase() == Phase::placing &&
rule.mayMoveInPlacingPhase)) {
rootPos->st.rule50 = static_cast<unsigned>(posKeyHistory.size());
}

Expand Down
6 changes: 3 additions & 3 deletions src/ui/qt/game_interaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ bool Game::validateClick(QPointF p, File &f, Rank &r)

bool Game::performAction(File f, Rank r, QPointF p)
{
// Judge whether to select, place or remove the piece
// Judge whether to select, place, move, or remove the piece
bool result = false;
PieceItem *piece;
QGraphicsItem *item = scene.itemAt(p, QTransform());
Expand All @@ -87,8 +87,8 @@ bool Game::performAction(File f, Rank r, QPointF p)
break;
}

// If the moving is not successful, try to reselect. There is no break
// here
// If placing is not successful, try to reselect or move. There is no
// break here
[[fallthrough]];

case Action::select:
Expand Down
5 changes: 5 additions & 0 deletions src/ui/qt/game_ui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,11 @@ void Game::setTips()
tips = turnStr + " to remove a piece. " +
std::to_string(p.pieceToRemoveCount[p.sideToMove]) +
" pieces can be removed.";
} else if (rule.mayMoveInPlacingPhase &&
(p.action == Action::select || p.action == Action::place)) {
tips = turnStr + " to place or move a piece. " +
std::to_string(p.pieceInHandCount[p.sideToMove]) +
" pieces remain unplaced.";
}
break;

Expand Down

0 comments on commit e3a7b4b

Please sign in to comment.