<commit_before>#include "Genes/King_Confinement_Gene.h"

#include <cmath>
#include <array>
#include <memory>
#include <map>
#include <algorithm>

#include "Genes/Gene.h"
#include "Game/Board.h"
#include "Game/Color.h"
#include "Game/Square.h"
#include "Game/Piece.h"

#include "Utility/Random.h"
#include "Utility/Math.h"

King_Confinement_Gene::King_Confinement_Gene() :
    friendly_block_score(0.0),
    opponent_block_score(0.0)
{
}

std::unique_ptr<Gene> King_Confinement_Gene::duplicate() const
{
    return std::make_unique<King_Confinement_Gene>(*this);
}

std::string King_Confinement_Gene::name() const
{
    return "King Confinement Gene";
}

void King_Confinement_Gene::load_properties(const std::map<std::string, double>& properties)
{
    Gene::load_properties(properties);
    friendly_block_score = properties.at("Friendly Block Score");
    opponent_block_score = properties.at("Opponent Block Score");
}

std::map<std::string, double> King_Confinement_Gene::list_properties() const
{
    auto properties = Gene::list_properties();
    properties["Friendly Block Score"] = friendly_block_score;
    properties["Opponent Block Score"] = opponent_block_score;
    return properties;
}

void King_Confinement_Gene::gene_specific_mutation()
{
    make_priority_minimum_zero();
    auto mutation_size = Random::random_laplace(2.0);
    switch(Random::random_integer(1, 2))
    {
        case 1:
            friendly_block_score += mutation_size;
            break;
        case 2:
            opponent_block_score += mutation_size;
            break;
        default:
            throw std::logic_error("Bad random value in King Confinement Gene");
    }
}

double King_Confinement_Gene::score_board(const Board& board, const Board& opposite_board, size_t) const
{
    // A flood-fill-like algorithm to count the squares that are reachable by the
    // king from its current positions with unlimited consecutive moves. The
    // boundaries of this area area squares attacked by the other color or occupied
    // by pieces of the same color.

    std::vector<Square> square_queue;
    square_queue.reserve(64);
    auto perspective = board.whose_turn();
    const auto& king_square = board.find_king(perspective);
    square_queue.push_back(king_square);

    std::array<int, 64> in_queue;
    in_queue.fill(false);
    in_queue[Board::square_index(king_square.file(), king_square.rank())] = true;

    auto squares_safe_for_king = opposite_board.squares_safe_for_king();

    double friendly_block_total = 0.0;
    double opponent_block_total = 0.0;
    int free_space_total = 0;

    for(size_t i = 0; i < square_queue.size(); ++i)
    {
        auto square = square_queue[i];
        auto square_index = Board::square_index(square.file(), square.rank());

        auto attacked_by_other = ! squares_safe_for_king[square_index];
        auto piece = board.piece_on_square(square.file(), square.rank());
        bool occupied_by_same = piece &&
                                piece->color() == perspective &&
                                piece->type() != KING;

        if(occupied_by_same)
        {
            friendly_block_total += friendly_block_score;
        }
        else if(attacked_by_other)
        {
            opponent_block_total += opponent_block_score;
        }
        else
        {
            ++free_space_total;
        }

        auto keep_going = (square == king_square) || (! occupied_by_same && ! attacked_by_other);

        // Add surrounding squares to square_queue.
        // always check the squares surrounding the king's current positions, even if
        // it is not safe (i.e., the king is in check).
        if(keep_going)
        {
            auto left_file = std::max('a', char(square.file() - 1));
            auto right_file = std::min('h', char(square.file() + 1));
            auto low_rank = std::max(1, square.rank() - 1);
            auto high_rank = std::min(8, square.rank() + 1);
            for(char new_file = left_file; new_file <= right_file; ++new_file)
            {
                for(int new_rank = low_rank; new_rank <= high_rank; ++new_rank)
                {
                    auto new_index = Board::square_index(new_file, new_rank);
                    if( ! in_queue[new_index])<commit_msg>Simplify King Confinement Gene<commit_after>#include "Genes/King_Confinement_Gene.h"

#include <cmath>
#include <array>
#include <memory>
#include <map>
#include <algorithm>

#include "Genes/Gene.h"
#include "Game/Board.h"
#include "Game/Color.h"
#include "Game/Square.h"
#include "Game/Piece.h"

#include "Utility/Random.h"
#include "Utility/Math.h"

King_Confinement_Gene::King_Confinement_Gene() :
    friendly_block_score(0.0),
    opponent_block_score(0.0)
{
}

std::unique_ptr<Gene> King_Confinement_Gene::duplicate() const
{
    return std::make_unique<King_Confinement_Gene>(*this);
}

std::string King_Confinement_Gene::name() const
{
    return "King Confinement Gene";
}

void King_Confinement_Gene::load_properties(const std::map<std::string, double>& properties)
{
    Gene::load_properties(properties);
    friendly_block_score = properties.at("Friendly Block Score");
    opponent_block_score = properties.at("Opponent Block Score");
}

std::map<std::string, double> King_Confinement_Gene::list_properties() const
{
    auto properties = Gene::list_properties();
    properties["Friendly Block Score"] = friendly_block_score;
    properties["Opponent Block Score"] = opponent_block_score;
    return properties;
}

void King_Confinement_Gene::gene_specific_mutation()
{
    make_priority_minimum_zero();
    auto mutation_size = Random::random_laplace(2.0);
    switch(Random::random_integer(1, 2))
    {
        case 1:
            friendly_block_score += mutation_size;
            break;
        case 2:
            opponent_block_score += mutation_size;
            break;
        default:
            throw std::logic_error("Bad random value in King Confinement Gene");
    }
}

double King_Confinement_Gene::score_board(const Board& board, const Board& opposite_board, size_t) const
{
    // A flood-fill-like algorithm to count the squares that are reachable by the
    // king from its current positions with unlimited consecutive moves. The
    // boundaries of this area area squares attacked by the other color or occupied
    // by pieces of the same color.

    std::vector<Square> square_queue;
    square_queue.reserve(64);
    auto perspective = board.whose_turn();
    const auto& king_square = board.find_king(perspective);
    square_queue.push_back(king_square);

    std::array<int, 64> in_queue{};
    in_queue[Board::square_index(king_square.file(), king_square.rank())] = true;

    const auto& squares_safe_for_king = opposite_board.squares_safe_for_king();

    double friendly_block_total = 0.0;
    double opponent_block_total = 0.0;
    int free_space_total = 0;

    for(size_t i = 0; i < square_queue.size(); ++i)
    {
        auto square = square_queue[i];
        auto square_index = Board::square_index(square.file(), square.rank());

        auto attacked_by_other = ! squares_safe_for_king[square_index];
        auto piece = board.piece_on_square(square.file(), square.rank());
        bool occupied_by_same = piece &&
                                piece->color() == perspective &&
                                piece->type() != KING;

        auto keep_going = square == king_square;
        if(occupied_by_same)
        {
            friendly_block_total += friendly_block_score;
        }
        else if(attacked_by_other)
        {
            opponent_block_total += opponent_block_score;
        }
        else
        {
            ++free_space_total;
            keep_going = true;
        }

        // Add surrounding squares to square_queue.
        // always check the squares surrounding the king's current positions, even if
        // it is not safe (i.e., the king is in check).
        if(keep_going)
        {
            auto left_file = std::max('a', char(square.file() - 1));
            auto right_file = std::min('h', char(square.file() + 1));
            auto low_rank = std::max(1, square.rank() - 1);
            auto high_rank = std::min(8, square.rank() + 1);
            for(char new_file = left_file; new_file <= right_file; ++new_file)
            {
                for(int new_rank = low_rank; new_rank <= high_rank; ++new_rank)
                {
                    auto new_index = Board::square_index(new_file, new_rank);
                    if( ! in_queue[new_index])
{'fraction_non_alphanumeric': 0.11392108652382625, 'fraction_numerical': 0.0060882800608828, 'mean_word_length': 2.952799629801018, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1063137', 'n_tokens_mistral': 2694, 'n_tokens_neox': 2579, 'n_words': 574}