#ifndef __PENGUIN_GENERAL_HEURISTIC_HPP__ #define __PENGUIN_GENERAL_HEURISTIC_HPP__ #include "penguin.hpp" #include "heuristic.hpp" #include "penguin_heuristic.hpp" #include <algorithm> #define MAX_NB_MOVES 60.0f //Count the number of direction in which a penguin can move uint8_t number_of_direction_penguin_general(uint32_t penguin){ uint8_t res = 0 ; if(PENGUIN_MOVES_A(penguin)>0) res++; if(PENGUIN_MOVES_B(penguin)>0) res++; if(PENGUIN_MOVES_C(penguin)>0) res++; if(PENGUIN_MOVES_D(penguin)>0) res++; if(PENGUIN_MOVES_E(penguin)>0) res++; if(PENGUIN_MOVES_F(penguin)>0) res++; return res; } namespace mcts { class generalization_heuristic : public penguin_heuristic { public: float get_value(const game::penguin& game, uint8_t move) const { float X_free_move=0.35, X_num_dir=0.15, X_points=0.2, X_zone=0.3; game::penguin g = *(game::copy(game)); auto old_state = g.get_state(); g.play(move); auto played_state = g.get_state(); uint32_t* penguins = played_state.current_player_red ? played_state.peng_red : played_state.peng_blue; uint32_t* other_peng = played_state.current_player_red ? played_state.peng_blue : played_state.peng_red; //Movement Freedom Heuristic float nb_moves_us = 0; float nb_moves_other = 0; for(int i=0; i< 4; i++) { nb_moves_us += PENGUIN_TOT_MOVES(penguins[i]); nb_moves_other += PENGUIN_TOT_MOVES(other_peng[i]); } float res_movement_freedom = -(nb_moves_us - nb_moves_other)/MAX_NB_MOVES; //Number Direction Freedom Heuristic uint8_t nb = 0; for(int i = 0; i < 4; ++i) { nb += number_of_direction_penguin_general(penguins[i]); } float res_number_direction_freedom = (-12.f + (float)nb)/12.f; //Points Heuristic const uint32_t* peng; uint16_t rel_move = move; float res_points =0.f; int i = 0; if(old_state.current_player_red) { for(i = 0; (i < 3) && (PENGUIN_TOT_MOVES(old_state.peng_red[i]) <= rel_move); i ++) rel_move -= PENGUIN_TOT_MOVES(old_state.peng_red[i]); peng = &new_state.peng_red[i]; } else { for(i = 0; (i < 3) && (PENGUIN_TOT_MOVES(old_state.peng_blue[i]) <= rel_move); i ++) rel_move -= PENGUIN_TOT_MOVES(old_state.peng_blue[i]); peng = &new_state.peng_blue[i]; } if((new_state.one_fish >> PENGUIN_POS(*peng)) & 1) res_points=1; else if((new_state.two_fish >> PENGUIN_POS(*peng)) & 1) res_points=0; else res_points=-1; //Zone Heuristic uint64_t moves_this = 0; uint64_t moves_other = 0; for(int i = 0; i < 4; ++i) { moves_this |= g.penguin_move_board(penguins[i]); moves_other |= g.penguin_move_board(other_peng[i]); } uint64_t this_owned_moves = moves_this & ~(moves_other); uint64_t other_owned_moves = moves_other & ~(moves_this); int count_this = 0; int count_other = 0; for(int i = 0; i < 60; i++) { count_this += (this_owned_moves>>i) & 1 ; count_other += (other_owned_moves>>i) & 1 ; } float res_zone = clamp((float)(count_this - count_other) / (count_this + 1), -1.f, 1.f); //Final Result return (X_free_move * res_movement_freedom + X_num_dir * res_number_direction_freedom + X_points * res_points + X_zone * res_zone); } int get_count(const game::penguin& game, uint8_t move) const { game::penguin g = *(game::copy(game)); auto old_state = g.get_state(); uint64_t obstacles = (~(old_state.one_fish | old_state.two_fish | old_state.three_fish)); for(int i = 0; i < 4; i++){ obstacles |= ((uint64_t) 1) << PENGUIN_POS(old_state.peng_red[i]); obstacles |= ((uint64_t) 1) << PENGUIN_POS(old_state.peng_blue[i]); } int nbr_obstacles = 0; // It count also the penguins so in this implementation it start at 8 + 1 for each move done for (int i =0; i<60; i++){ if((obstacles >> i) & 1) nbr_obstacles++; } return ((int)ceil(500.0/nbr_obstacles)); } private: float clamp(float v, float l, float h) const { return std::max(std::min(h,v),l); } }; }; #endif