// - - - - - - - - - - - - - - - - - - // File: creature.cpp | // Purpose: implements class Creature | // Author: Taivo Lints, Estonia | // Date: May, 2003 | // Copyright: see copyright.txt | // - - - - - - - - - - - - - - - - - - #include "creature.h" #include "ann/neuralnetwork.h" #include "allegro.h" using namespace std; // - - - - - Class Creature - - - - - // ****************************** // * Construction & Destruction * // ****************************** // - Creature constructor - - // Needs a pointer to the bitmap this creature will "live" on. // Also needs the palette colors for inner and outer circles of sensors, // start of light's color gradient on palette, and a configuration file // for neural network. Creature::Creature(BITMAP* inp_pArena, int c_of_icircle, int c_of_ocircle, int s_of_gradient, char* conf_file) { pArena = inp_pArena; x = pArena->w / 2; y = pArena->h / 2; speed_x = 0; speed_y = 0; speedup_factor = 3; color_of_icircle = c_of_icircle; color_of_ocircle = c_of_ocircle; start_of_gradient = s_of_gradient; // Currently the number of inputs (sensors) MUST be 3: // lower left, upper and lower right sensor (in that order). v_dbl_inps.assign(3, 0); // Sets the relative positions of these three sensors. Position* pPos = new Position; pPos->x = -4; pPos->y = 3; vPositions.push_back(*pPos); delete pPos; pPos = new Position; pPos->x = 0; pPos->y = -5; vPositions.push_back(*pPos); delete pPos; pPos = new Position; pPos->x = 4; pPos->y = 3; vPositions.push_back(*pPos); delete pPos; // Outputs are: speed_left, speed_right, speed_up, speed_down (in this order). // Speed_x is calculated as speed_right - speed_left. Similar formula for y. v_dbl_outputs.assign(4, 0); // Creates network and checks its correctness. pNet = new NeuralNetwork(conf_file); if( (pNet->get_number_of_inputs() != 3) or (pNet->get_number_of_outputs() != 4) ) flag_incor_net = true; else flag_incor_net = false; } // - Creature copy-constructor - - Creature::Creature(const Creature& rC) { // Copy of creature can currently live only on the same bitmap as original. pArena = rC.pArena; x = rC.x; y = rC.y; speed_x = rC.speed_x; speed_y = rC.speed_y; speedup_factor = rC.speedup_factor; color_of_icircle = rC.color_of_icircle; color_of_ocircle = rC.color_of_ocircle; start_of_gradient = rC.start_of_gradient; v_dbl_inps = rC.v_dbl_inps; vPositions = rC.vPositions; v_dbl_outputs = rC.v_dbl_outputs; // Must have its own network. pNet = new NeuralNetwork(NULL); *pNet = *(rC.pNet); // Fortunately I wrote operator= overloading for // NeuralNetwork class :) (otherwise it wouldn't // work correctly). // It's safer to check the correctness again than just copy flag_incor_net. if( (pNet->get_number_of_inputs() != 3) or (pNet->get_number_of_outputs() != 4) ) flag_incor_net = true; else flag_incor_net = false; } // - Operator= overloading - - Creature& Creature::operator=(const Creature& rC) { if(&rC != this) { // Check for self-assignment. pArena = rC.pArena; x = rC.x; y = rC.y; speed_x = rC.speed_x; speed_y = rC.speed_y; speedup_factor = rC.speedup_factor; color_of_icircle = rC.color_of_icircle; color_of_ocircle = rC.color_of_ocircle; start_of_gradient = rC.start_of_gradient; v_dbl_inps = rC.v_dbl_inps; vPositions = rC.vPositions; v_dbl_outputs = rC.v_dbl_outputs; // Must have its own network. pNet = new NeuralNetwork(NULL); *pNet = *(rC.pNet); // Fortunately I wrote operator= overloading for // NeuralNetwork class :) (otherwise it wouldn't // work correctly). // It's safer to check the correctness again than just copy flag_incor_net. if( (pNet->get_number_of_inputs() != 3) or (pNet->get_number_of_outputs() != 4) ) flag_incor_net = true; else flag_incor_net = false; } return *this; } // - Creature destructor - - Creature::~Creature() { // Deletes network (to prevent memory leak). delete pNet; } // ************* // * Functions * // ************* // - Function: update - - // Updates creature position. void Creature::update() { // Updates only when neural network is correct. if(not flag_incor_net) { int ix = static_cast<int>(x); int iy = static_cast<int>(y); // Reads and normalizes sensor information. for(int i = 0; i < 3; i++) { int light_intensity = getpixel(pArena, ix + vPositions[i].x, iy + vPositions[i].y) - start_of_gradient; if(light_intensity < 0) light_intensity = 0; if(light_intensity > 64) light_intensity = 64; v_dbl_inps[i] = static_cast<double>(light_intensity) / 64; } // Uses network. pNet->set_inputs(&v_dbl_inps); pNet->update(); pNet->get_outputs(&v_dbl_outputs); // Updates speed and position. speed_x = (v_dbl_outputs[1] - v_dbl_outputs[0]) * speedup_factor; speed_y = (v_dbl_outputs[3] - v_dbl_outputs[2]) * speedup_factor; x += speed_x; y += speed_y; // Keep creature on screen if(x + vPositions[0].x < 0) x = 0 - vPositions[0].x; if(x + vPositions[2].x > pArena->w - 1) x = pArena->w - 1 - vPositions[2].x; if(y + vPositions[1].y < 0) y = 0 - vPositions[1].y; if(y + vPositions[0].y > pArena->h - 1) y = pArena->h - 1 - vPositions[0].y; } } // - Function: draw - - // Draws creature on the bitmap. void Creature::draw() { int ix = static_cast<int>(x); int iy = static_cast<int>(y); circle(pArena, ix + vPositions[0].x, iy + vPositions[0].y, 1, color_of_icircle); circle(pArena, ix + vPositions[0].x, iy + vPositions[0].y, 2, color_of_ocircle); circle(pArena, ix + vPositions[1].x, iy + vPositions[1].y, 1, color_of_icircle); circle(pArena, ix + vPositions[1].x, iy + vPositions[1].y, 2, color_of_ocircle); circle(pArena, ix + vPositions[2].x, iy + vPositions[2].y, 1, color_of_icircle); circle(pArena, ix + vPositions[2].x, iy + vPositions[2].y, 2, color_of_ocircle); } // - Function: load_network - - // Loads a new network into creature. void Creature::load_network(char* config_file) { delete pNet; pNet = new NeuralNetwork(config_file); // Checks correctness. if( (pNet->get_number_of_inputs() != 3) or (pNet->get_number_of_outputs() != 4) ) flag_incor_net = true; else flag_incor_net = false; }