big refactoring: put everything in model to allow

for better mvc structure (yes i'm doing view in cpp)
This commit is contained in:
Karma Riuk
2025-02-06 16:15:56 +01:00
parent 1231e4da92
commit 72f3431418
20 changed files with 45 additions and 40 deletions

View File

@ -0,0 +1,23 @@
#include "../board/board.hpp"
#include "../utils/coords.hpp"
#include "../utils/move.hpp"
#include "piece.hpp"
#include <vector>
std::vector<Move> bishop_moves(const Board& b, const Coords xy) {
std::vector<Move> ret;
auto ne = look_direction(b, xy, 1, 1);
ret.insert(ret.end(), ne.begin(), ne.end());
auto se = look_direction(b, xy, 1, -1);
ret.insert(ret.end(), se.begin(), se.end());
auto sw = look_direction(b, xy, -1, -1);
ret.insert(ret.end(), sw.begin(), sw.end());
auto nw = look_direction(b, xy, -1, 1);
ret.insert(ret.end(), nw.begin(), nw.end());
return ret;
}

View File

@ -0,0 +1,75 @@
#include "../board/board.hpp"
#include "../utils/coords.hpp"
#include "../utils/move.hpp"
#include "piece.hpp"
static bool is_clear_king_side(const Board& b, const Coords xy) {
for (int dx = 1; dx < 3; dx++) {
Coords c{xy.x + dx, xy.y};
if (b.squares[c.to_index()] != Piece::None)
return false;
std::optional<Move> move = move_for_position(b, xy, c);
Board board_after_move = b.make_move(move.value());
if (board_after_move.is_check_for(b.colour_at(xy)))
return false;
}
return true;
}
static bool is_clear_queen_side(const Board& b, const Coords xy) {
for (int dx = 1; dx < 4; dx++) {
Coords c{xy.x - dx, xy.y};
if (b.squares[c.to_index()] != Piece::None)
return false;
std::optional<Move> move = move_for_position(b, xy, c);
Board board_after_move = b.make_move(move.value());
if (dx < 3 && board_after_move.is_check_for(b.colour_at(xy)))
return false;
}
return true;
}
std::vector<Move> king_moves(const Board& b, const Coords xy) {
std::vector<Move> ret;
// -- Regular moves
for (int dx = -1; dx <= 1; dx++) {
for (int dy = -1; dy <= 1; dy++) {
if (dx == 0 && dy == 0) // skip staying in the same position
continue;
Coords c{xy.x + dx, xy.y + dy};
std::optional<Move> move = move_for_position(b, xy, c);
if (move.has_value())
ret.push_back(move.value());
}
}
if (b.is_check_for(b.colour_at(xy)))
return keep_only_blocking(ret, b);
// -- Castles
int8_t castling_rights = b.colour_at(xy) == Colour::White
? b.w_castle_rights
: b.b_castle_rights;
if (castling_rights == CastleSide::NeitherSide)
return ret;
if (castling_rights & CastleSide::KingSide && is_clear_king_side(b, xy)) {
ret.push_back(Move{
xy.to_index(),
Coords{6, xy.y}.to_index(),
});
}
if (castling_rights & CastleSide::QueenSide && is_clear_queen_side(b, xy)) {
ret.push_back(Move{
xy.to_index(),
Coords{2, xy.y}.to_index(),
});
}
return ret;
}

View File

@ -0,0 +1,28 @@
#include "../board/board.hpp"
#include "../utils/coords.hpp"
#include "../utils/move.hpp"
#include "piece.hpp"
#include <vector>
std::vector<Move> knight_moves(const Board& b, const Coords xy) {
std::vector<Move> ret;
std::vector<std::pair<int, int>> moves = {
{+2, +1},
{+1, +2}, // north east
{+2, -1},
{+1, -2}, // south east
{-2, -1},
{-1, -2}, // south west
{-2, +1},
{-1, +2} // north west
};
for (const auto& [dx, dy] : moves) {
std::optional<Move> move =
move_for_position(b, xy, Coords{xy.x + dx, xy.y + dy});
if (move.has_value())
ret.push_back(move.value());
}
return ret;
}

View File

@ -0,0 +1,83 @@
#include "../board/board.hpp"
#include "../utils/coords.hpp"
#include "../utils/move.hpp"
#include "piece.hpp"
std::vector<Move> pawn_moves(const Board& b, const Coords xy) {
std::vector<Move> ret{};
int8_t my_colour = b.colour_at(xy);
// -- Capture to the left
if (xy.x > 0) {
int dy = my_colour == Colour::White ? 1 : -1;
Coords left{xy.x - 1, xy.y + dy};
int8_t capturable_piece = b.squares[left.to_index()];
if (capturable_piece != 0) {
if (my_colour != b.colour_at(left))
if ((my_colour == White && left.y == 7)
|| (my_colour == Black && left.y == 0))
for (auto piece : {Rook, Knigt, Bishop, Queen})
ret.push_back(Move{
xy.to_index(),
left.to_index(),
(int8_t) (my_colour | piece)
});
else
ret.push_back(Move{xy.to_index(), left.to_index()});
}
}
// -- Capture to the right
if (xy.x < 7) {
int dy = my_colour == Colour::White ? 1 : -1;
Coords right{xy.x + 1, xy.y + dy};
int8_t capturable_piece = b.squares[right.to_index()];
if (capturable_piece != 0) {
if (my_colour != b.colour_at(right))
if ((my_colour == White && right.y == 7)
|| (my_colour == Black && right.y == 0))
for (auto piece : {Rook, Knigt, Bishop, Queen})
ret.push_back(Move{
xy.to_index(),
right.to_index(),
(int8_t) (my_colour | piece)
});
else
ret.push_back(Move{xy.to_index(), right.to_index()});
}
}
// -- Capture en passant
if (b.en_passant_target != -1) {
Coords c = Coords::from_index(b.en_passant_target);
int dy = my_colour == Colour::White ? 1 : -1;
if (c.y == xy.y + dy && (c.x == xy.x - 1 || c.x == xy.x + 1))
ret.push_back(Move{xy.to_index(), c.to_index()});
}
// -- Normal move + promotion
bool is_on_starting_rank =
my_colour == Colour::White ? xy.y == 1 : xy.y == 6;
int max_dy = is_on_starting_rank ? 3 : 2;
for (int dy = 1; dy < max_dy; dy++) {
int actual_dy = my_colour == Colour::White ? dy : -dy;
Coords new_xy{xy.x, xy.y + actual_dy};
if (b.squares[new_xy.to_index()] != Piece::None)
break;
if (new_xy.y == 7 || new_xy.y == 0)
for (auto piece : {Rook, Knigt, Bishop, Queen})
ret.push_back(Move{
xy.to_index(),
new_xy.to_index(),
.promoting_to = (int8_t) (my_colour | piece)
});
else
ret.push_back(Move{
xy.to_index(),
new_xy.to_index(),
});
}
return ret;
}

View File

@ -0,0 +1,82 @@
#include "piece.hpp"
#include "../board/board.hpp"
#include "../utils/coords.hpp"
#include "../utils/move.hpp"
std::vector<Move>
keep_only_blocking(const std::vector<Move> candidates, const Board& board) {
if (candidates.size() == 0)
return {};
int8_t my_colour = board.colour_at(candidates[0].source_square);
std::vector<Move> ret;
for (Move move : candidates) {
Board board_after_move = board.make_move(move);
if (!board_after_move.is_check_for(my_colour))
ret.push_back(move);
}
return ret;
}
std::vector<Move>
legal_moves(int8_t p, const Board& b, const Coords xy, bool looking_for_check) {
std::vector<Move> ret;
int8_t simple_piece = p & 0b00111;
switch (simple_piece) {
case Piece::Pawn:
ret = pawn_moves(b, xy);
break;
case Piece::Bishop:
ret = bishop_moves(b, xy);
break;
case Piece::Rook:
ret = rook_moves(b, xy);
break;
case Piece::Knigt:
ret = knight_moves(b, xy);
break;
case Piece::Queen:
ret = queen_moves(b, xy);
break;
case Piece::King:
ret = king_moves(b, xy);
break;
default:
break;
}
if (!looking_for_check)
return keep_only_blocking(ret, b);
return ret;
}
std::optional<Move>
move_for_position(const Board& board, const Coords source, const Coords dest) {
if (!dest.is_within_bounds()
|| board.colour_at(source) == board.colour_at(dest))
return {};
return Move{source.to_index(), dest.to_index()};
}
std::vector<Move>
look_direction(const Board& board, const Coords xy, int mult_dx, int mult_dy) {
std::vector<Move> ret;
for (int d = 1; d < 8; d++) {
int dx = mult_dx * d;
int dy = mult_dy * d;
Coords target{xy.x + dx, xy.y + dy};
std::optional<Move> move = move_for_position(board, xy, target);
if (move.has_value()) {
ret.push_back(move.value());
if (board.squares[target.to_index()] != Piece::None)
break;
} else {
break;
}
}
return ret;
}

View File

@ -0,0 +1,42 @@
#pragma once
#include <cstdint>
#include <optional>
#include <ostream>
#include <vector>
enum Piece : int8_t {
None = 0,
Rook = 1,
Knigt = 2,
Bishop = 3,
Queen = 4,
King = 5,
Pawn = 6,
};
enum Colour : int8_t {
White = 8,
Black = 16,
};
inline std::ostream& operator<<(std::ostream& os, const int8_t& i) {
os << std::to_string(i);
return os;
}
class Board;
struct Coords;
struct Move;
std::vector<Move> legal_moves(int8_t, const Board&, const Coords, bool = false);
std::vector<Move> keep_only_blocking(const std::vector<Move>, const Board&);
std::optional<Move> move_for_position(const Board&, const Coords, const Coords);
std::vector<Move> look_direction(const Board&, const Coords, int, int);
std::vector<Move> pawn_moves(const Board&, const Coords);
std::vector<Move> rook_moves(const Board&, const Coords);
std::vector<Move> knight_moves(const Board&, const Coords);
std::vector<Move> bishop_moves(const Board&, const Coords);
std::vector<Move> queen_moves(const Board&, const Coords);
std::vector<Move> king_moves(const Board&, const Coords);

View File

@ -0,0 +1,35 @@
#include "../board/board.hpp"
#include "../utils/coords.hpp"
#include "../utils/move.hpp"
#include "piece.hpp"
#include <vector>
std::vector<Move> queen_moves(const Board& b, const Coords xy) {
std::vector<Move> ret;
auto e = look_direction(b, xy, 1, 0);
ret.insert(ret.end(), e.begin(), e.end());
auto s = look_direction(b, xy, 0, -1);
ret.insert(ret.end(), s.begin(), s.end());
auto w = look_direction(b, xy, -1, 0);
ret.insert(ret.end(), w.begin(), w.end());
auto n = look_direction(b, xy, 0, 1);
ret.insert(ret.end(), n.begin(), n.end());
auto ne = look_direction(b, xy, 1, 1);
ret.insert(ret.end(), ne.begin(), ne.end());
auto se = look_direction(b, xy, 1, -1);
ret.insert(ret.end(), se.begin(), se.end());
auto sw = look_direction(b, xy, -1, -1);
ret.insert(ret.end(), sw.begin(), sw.end());
auto nw = look_direction(b, xy, -1, 1);
ret.insert(ret.end(), nw.begin(), nw.end());
return ret;
}

View File

@ -0,0 +1,23 @@
#include "../board/board.hpp"
#include "../utils/coords.hpp"
#include "../utils/move.hpp"
#include "piece.hpp"
#include <vector>
std::vector<Move> rook_moves(const Board& b, const Coords xy) {
std::vector<Move> ret;
auto e = look_direction(b, xy, 1, 0);
ret.insert(ret.end(), e.begin(), e.end());
auto s = look_direction(b, xy, 0, -1);
ret.insert(ret.end(), s.begin(), s.end());
auto w = look_direction(b, xy, -1, 0);
ret.insert(ret.end(), w.begin(), w.end());
auto n = look_direction(b, xy, 0, 1);
ret.insert(ret.end(), n.begin(), n.end());
return ret;
}