/
moshroom_edu
/
evolution
Обзор
Документация
Войти
/
moshroom_edu
/
evolution
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
master
src/bact_engine/neuro_bact.cpp
468 строк
13 KB
mushroom
bkp
26 июн 2026, 08:34
26 июн 2026, 08:34
84517f4
Код
Авторство
О чём код?
#include "bact_engine/neuro_bact.h" #include "neuro_engine/ann.h" #include "bact_engine/poper.h" #include "bact_engine/engine.h" namespace b_engine { static const float view_dist_sq = g_view_dist * g_view_dist; static std::vector< sf::Vector2f > sensors = []() { std::vector< sf::Vector2f > sensors; sensors.resize( 35 ); for( ull i = 0; i < 35; ++i ) { sf::Vector2f& v = sensors[ i ]; v.x = g_view_dist * std::cos( 2 * g_pi * ( static_cast< float >( i ) / 35 ) ); v.y = g_view_dist * std::sin( 2 * g_pi * ( static_cast< float >( i ) / 35 ) ); } return sensors; }(); neuro_bact::neuro_bact() { //m_input.resize(); m_output.resize( 3 ); set_color( sf::Color( 255, 0, 0 ) ); } neuro_bact::~neuro_bact() {} sf::Vector2f trace_sensor( float x1, float y1, float x2, float y2, float xC, float yC, float R ) { x1 -= xC; y1 -= yC; x2 -= xC; y2 -= yC; float A = y2 - y1; //A в уравнении прямой float B = x2 - x1; //В в уравнении прямой float C = x1 * y2 - x2 * y1; // C float CC = C * C; float RR = R * R; float a_b_sq = ( A * A + B * B ); float x0 = -A * C / a_b_sq; float y0 = -B * C / a_b_sq; if( CC > RR * a_b_sq + g_EPS ) { return sf::Vector2f( 0, 0 ); } if( std::fabs( CC - RR * a_b_sq ) < g_EPS ) { return sf::Vector2f( x0 + xC, y0 + yC ); } float d = RR - CC / a_b_sq; float mult = std::sqrt( d / a_b_sq ); float ax, ay, bx, by; ax = x0 + B * mult + xC; bx = x0 - B * mult + xC; ay = y0 - A * mult + yC; by = y0 + A * mult + yC; return sqare_distance( x1, y1, ax, ay ) < sqare_distance( x1, y1, bx, by ) ? sf::Vector2f( ax, ay ) : sf::Vector2f( bx, by ); } void neuro_bact::think( const std::vector< object_ptr >& objects ) { std::vector< object_ptr > vis; float mx = x(); float my = y(); //set_force(0,0); for( const auto& ob : objects ) { if( ob && ob.get() != this && ( sqare_distance( mx, my, ob->x(), ob->y() ) < ( view_dist_sq + std::pow( ob->radius(), 2. ) ) ) ) { vis.push_back( ob ); } } std::sort( vis.begin(), vis.end(), [ mx, my ]( const object_ptr& a, const object_ptr& b ) { return sqare_distance( mx, my, a->x(), a->y() ) < sqare_distance( mx, my, b->x(), b->y() ); } ); float ox; float oy; float obr; sf::Vector2f res; m_input.pop_back(); m_input.pop_back(); m_input.pop_back(); for( long long int i = 2; i >= 0; --i ) { size_t shift = ( m_input.size() / 4 ); size_t offset = i * shift; for( size_t j = 0; j < shift; ++j ) { size_t from_idx = offset + j; size_t to_idx = offset + j + shift; double& from = m_input[ from_idx ]; double& to = m_input[ to_idx ]; to = from; from = 0.; } } const auto& color = get_color(); m_input.push_back( color.r ); m_input.push_back( color.g ); m_input.push_back( color.b ); for( const auto& ob : vis ) { ox = ob->x(); oy = ob->y(); obr = ob->radius(); const sf::Color& color = ob->get_color(); ull k = 0; if( ox > mx && oy > my ) k = 0; else if( ox < mx && oy > my ) k = 9; else if( ox < mx && oy < my ) k = 18; else if( ox > mx && oy < my ) k = 27; ull count = k + ( k == 27 ? 8 : 9 ); size_t i = k * 3; for( ull j = k; j < count; ++j ) { const auto& s = sensors[ j ]; res = trace_sensor( mx, my, s.x + mx, s.y + my, ox, oy, obr ); if( res.x != 0.f && res.y != 0.f ) // it's ok! 0.f 0.f will returned only if no intersection { float dist_s = sqare_distance( mx, my, res.x, res.y ); float dist_m = dist_s / view_dist_sq; float bright = dist_m > 1. ? 0 : 1.f - dist_m; float r = bright * ( float( color.r ) / 255 ); float g = bright * ( float( color.g ) / 255 ); float b = bright * ( float( color.b ) / 255 ); m_input[ i ] = static_cast< double >( r ); m_input[ i + 1 ] = static_cast< double >( g ); m_input[ i + 2 ] = static_cast< double >( b ); assert( m_input[ i ] <= 1. ); assert( m_input[ i ] >= 0. ); assert( m_input[ i + 1 ] <= 1. ); assert( m_input[ i + 1 ] >= 0. ); assert( m_input[ i + 2 ] <= 1. ); assert( m_input[ i + 2 ] >= 0. ); } i += 3; } } float wall_left = g_view_dist / 3; float wall_right = g_world_width - g_view_dist / 3; float wall_top = g_view_dist / 3; float wall_bottom = g_world_height - g_view_dist / 3; //TODO optimize by quarter //check sensors tracing on "out of world" if( mx < wall_left || mx > wall_right || my < wall_top || my > wall_bottom ) { float t_x = 0; float t_y = 0; size_t i = 0; for( const auto& sensor : sensors ) { t_x = sensor.x + mx; t_y = sensor.y + my; if( t_x < 0 || t_x > g_world_width || t_y < 0 || t_y > g_world_height ) { if( m_input[ i ] < 0.01 && m_input[ i + 1 ] < 0.01 && m_input[ i + 2 ] < 0.01 ) { m_input[ i ] = 0.; m_input[ i + 1 ] = 1.; m_input[ i + 2 ] = 1.; } } i += 3; } } ull offset = sensors.size() * 3; for( int i = 0; i < 5; ++i ) { m_input[ offset++ ] = static_cast< double >( 0 /*mx / g_world_width*/ ); m_input[ offset++ ] = static_cast< double >( 0 /*my / g_world_height*/ ); m_input[ offset++ ] = static_cast< double >( speed_x() / 100 ); m_input[ offset++ ] = static_cast< double >( speed_y() / 100 ); m_input[ offset++ ] = static_cast< double >( m_fx / g_max_force ); m_input[ offset++ ] = static_cast< double >( m_fy / g_max_force ); m_input[ offset++ ] = static_cast< double >( accel_x() / 100 ); m_input[ offset++ ] = static_cast< double >( accel_y() / 100 ); m_input[ offset++ ] = static_cast< double >( 1. - energy() / g_bact_max_mass ); m_input[ offset++ ] = std::sin( 6.28 * double( engine::instance().ticks_couner() % 100 ) / 100. ); } m_brain->set_input( m_input ); m_brain->process(); m_brain->get_output( m_output ); double& first = m_output[ 0 ]; if( first > 0.5 ) { first = 1.; } else if( first < -0.5 ) { first = -1.; } else { first = 0.; } double& second = m_output[ 1 ]; if( second > 0.5 ) { second = 1.; } else if( second < -0.5 ) { second = -1.; } else { second = 0.; } // bact::think(objects); // return; //FOR DEBUG SENSORS switch( g_physic_type ) { case physic_type::teleport: { auto _x = x(); auto _y = y(); set_pos( _x + static_cast< float >( m_output[ 0 ] ) * g_view_dist, _y + static_cast< float >( m_output[ 1 ] ) * g_view_dist ); break; } case physic_type::speed: { set_speed( static_cast< float >( m_output[ 0 ] ) * g_max_force / 2.f, static_cast< float >( m_output[ 1 ] ) * g_max_force / 2.f ); break; } case physic_type::force: { double mul = 1; set_force( static_cast< float >( ( m_output[ 0 ] ) ) * g_max_force * mul, static_cast< float >( ( m_output[ 1 ] ) ) * g_max_force * mul ); break; } } } void neuro_bact::respawn() { bact::respawn(); m_d_reason = death_reason::none; m_age = 0; //set_color(sf::Color(255,255,255)); for( auto& v_o : m_output ) { v_o = 0.; } } void neuro_bact::on_draw( sf::RenderWindow& window ) { sf::Vertex line[ 2 ]; ull i = 0; for( const auto& v : sensors ) { int r = m_input[ i ] * 255; int g = m_input[ i + 1 ] * 255; int b = m_input[ i + 2 ] * 255; sf::Color vertex_color( r, g, b ); line[ 0 ] = sf::Vertex( sf::Vector2f( x(), y() ), vertex_color ); line[ 1 ] = sf::Vertex( sf::Vector2f( v.x + x(), v.y + y() ), vertex_color ); window.draw( line, 2, sf::Lines ); i += 3; } sf::CircleShape c; c.setPosition( x(), y() ); c.setFillColor( get_color() ); float r = radius(); c.setRadius( r ); c.setOrigin( r, r ); window.draw( c ); sf::Text t; t.setCharacterSize( 12 ); t.setFont( g_font ); t.setFillColor( sf::Color( 255, 255, 255 ) ); t.setString( "I: " + std::to_string( population_index() ) + "\nScore:" + std::to_string( m_score ) + "\nE:" + std::to_string( int( energy() ) ) + "\nA:" + std::to_string( m_age ) ); t.setPosition( x(), y() ); window.draw( t ); } void neuro_bact::on_destroy() {} void neuro_bact::on_collision( const object_ptr obj ) { bact::on_collision( obj ); if( obj->type() == object_type::bact ) { if( mass() < obj->mass() ) { m_d_reason = death_reason::eatten; //m_score *= 0.7; } /*else { m_score += std::static_pointer_cast<bact>(obj)->mass(); }*/ } else if( obj->type() == object_type::leaf ) { m_score += obj->mass(); } } void neuro_bact::on_update( const std::vector< object_ptr >& objects ) { bact::on_update( objects ); if( x() < 0 || x() > g_world_width || y() < 0 || y() > g_world_height ) { //m_score = 0; m_d_reason = death_reason::leave_world; destroy(); //delta_mass(-5.); } if( mass() < g_bact_death_mass ) { m_d_reason = death_reason::hungry; //m_score /= 2; } else if( energy() > g_bact_max_mass ) { m_d_reason = death_reason::so_fat; destroy(); if( engine::instance().is_drawing() ) { auto pop = std::make_shared< poper >( radius(), x(), y() ); engine::instance().add_object( pop ); } } if( m_age > g_bact_max_age ) { m_d_reason = death_reason::so_old; destroy(); } double temp = energy() / 1000; uint8_t color = temp * 127; if( m_age > g_age_of_adult ) { set_color( sf::Color( 120 + color, 50, 0 ) ); } else { set_color( sf::Color( 120 + color, 120, 0 ) ); } ++m_age; //if( ! (engine::instance().ticks_couner() % 25)) ++m_score; // ++m_score; } ull neuro_bact::population_index() const { return m_population_index; } void neuro_bact::set_population_index( const ull& pop_index ) { m_population_index = pop_index; } lli neuro_bact::score() const { return m_score; } void neuro_bact::set_score( lli score ) { m_score = score; } void neuro_bact::delta_score( lli delta ) { m_score += delta; } std::shared_ptr< n_engine::ann > neuro_bact::brain() const { return m_brain; } void neuro_bact::set_brain( const std::shared_ptr< n_engine::ann >& brain ) { m_brain = brain; m_input.resize( m_brain->layers()[ 0 ].size() ); } } //namespace b_engine ////составляем коэффициенты квадратного уравнения на пересечение прямой и окружности. ////если на отрезке [0..1] есть отрицательные значения, значит отрезок пересекает окружность //float a = dx * dx + dy * dy; //float b = 2.f * (x1 * dx + y1 * dy); //float c = x1 * x1 + y1 * y1 - R*R; ////а теперь проверяем, есть ли на отрезке [0..1] решения //bool res; //if (-b < 0) // res = (c < 0); //else if (-b < (2.f*a)) // res = ((4.f * a * c - b * b) < 0); // else res = (a+b+c < 0);