From e6ab4a8ed100d5d5b7611c74cf3ccd556f1f1d71 Mon Sep 17 00:00:00 2001 From: Paul Oliver Date: Thu, 29 Feb 2024 19:04:34 +0100 Subject: Initial commit --- plugins/CppnExplorer/src/CppnExplorer.cpp | 549 ++++++++++++++++++++++++++++++ 1 file changed, 549 insertions(+) create mode 100644 plugins/CppnExplorer/src/CppnExplorer.cpp (limited to 'plugins/CppnExplorer/src/CppnExplorer.cpp') diff --git a/plugins/CppnExplorer/src/CppnExplorer.cpp b/plugins/CppnExplorer/src/CppnExplorer.cpp new file mode 100644 index 0000000..555922a --- /dev/null +++ b/plugins/CppnExplorer/src/CppnExplorer.cpp @@ -0,0 +1,549 @@ +#include +#include +#include + +using namespace sf; +using namespace hyperneat; + +CppnExplorer::CppnExplorer() +{ + _fieldSprite.setOrigin(1.0f, 1.0f); + _fieldSprite.setPosition(0.0f, 0.0f); + _fieldSprite.setTexture(&_fieldTexture); + _fieldSprite.setSize(Vector2f(2.0f, 2.0f)); + _fieldImage.create(RESOLUTION, RESOLUTION); +} + +CppnExplorer::~CppnExplorer() +{ + shutdown(); +} + +void +CppnExplorer::run(const Genome& genome, const NeuralNetPrms* nnPrms, RenderTarget* target) +{ + shutdown(); + _target = target; + _genome = genome; + + _cppn.clear(); + _cppn.create(_genome); + + if (nnPrms) { + _withNeuralNet = true; + _nnPrms = *nnPrms; + _neuralNetGenerator = Thread(&CppnExplorer::neuralNetGenerator, this); + } + + if (!_target) { + _windowOpen = true; + _target = &_window; + _windowHandler = Thread(&CppnExplorer::windowHandler, this); + } + + _fieldGenerator = Thread(&CppnExplorer::fieldGenerator, this); +} + +void +CppnExplorer::shutdown() +{ + if (_neuralNetGenerator.joinable()) { + _neuralNetGenerator.join(); + } + + if (_windowHandler.joinable()) { + _windowOpen = false; + _windowHandler.join(); + } + + _neurons.clear(); + _withNeuralNet = false; + _neuralNetReady = false; + _windowOpen = false; + _target = nullptr; +} + +void +CppnExplorer::draw() +{ + _target->clear({8, 8, 16}); + + if (_neuralNetReady) { + for (auto& i : _neurons) { + _target->draw(i._synapses, BlendAdd); + } + + for (auto& i : _neurons) { + _target->draw(i._nucleus, BlendAdd); + } + } + + if (_windowOpen) { + _window.display(); + } +} + +void +CppnExplorer::windowHandler() +{ + ContextSettings settings(0, 0, 8); + String title("Cppn Explorer"); + View view({-1.0f, -1.0f, 2.0f, 2.0f}); + VideoMode videoMode(RESOLUTION, RESOLUTION); + Uint32 style(Style::Titlebar | Style::Close); + + _window.create(videoMode, title, style, settings); + _window.setVerticalSyncEnabled(true); + _window.setView(view); + + while (_windowOpen) { + eventHandler(); + draw(); + } +} + +void +CppnExplorer::eventHandler() +{ + Event event; + + while (_window.pollEvent(event)) { + switch (event.type) { + case Event::Closed: + _windowOpen = false; + break; + + default:; + } + } +} + +void +CppnExplorer::neuralNetGenerator() +{ + _neuralNet.clear(); + _neuralNet.create(_cppn, _nnPrms); + + _neurons.reserve(_neuralNet.getNeurons().size()); + + for (auto& i : _neuralNet.getNeurons()) { + _neurons.emplace_back(i); + } + + _neuralNetReady = true; +} + +void +CppnExplorer::fieldGenerator() +{ + +} + +CppnExplorer::Neuron::Neuron(const NeuralNet::Neuron& refNeuron) +{ + _nucleus.setPosition(refNeuron._position._x, refNeuron._position._y); + _nucleus.setOrigin(_nucleus.getRadius(), _nucleus.getRadius()); + + Color nColor = (refNeuron._bias > 0.0 ? Color::White : Color::Red); + nColor.a = static_cast(fabs((refNeuron._bias / 3.0) * 112.0) + 16.0); + _nucleus.setFillColor(nColor); + + switch (refNeuron._type) { + case NeuralNet::Neuron::Type::INPUT: + _nucleus.setOutlineThickness(4.0f * PIXEL_SIZE); + _nucleus.setOutlineColor({255, 255, 255, nColor.a}); + break; + + case NeuralNet::Neuron::Type::OUTPUT: + _nucleus.setOutlineThickness(4.0f * PIXEL_SIZE); + _nucleus.setOutlineColor({255, 0, 0, nColor.a}); + break; + + default:; + } + + for (auto& i : refNeuron._synapses) { + auto iNeuron = *i._neuron; + Color sColor = (i._weight > 0.0 ? Color::White : Color::Red); + sColor.a = static_cast(fabs((i._weight / 3.0) * 112.0) + 16.0); + Vector2f iPos = {static_cast(iNeuron._position._x), static_cast(iNeuron._position._y)}; + Vector2f tPos = {static_cast(refNeuron._position._x), static_cast(refNeuron._position._y)}; + + _synapses.append({iPos, sColor}); + _synapses.append({tPos, sColor}); + } +} + +// void +// CppnExplorer::run(const Genome& genome, const NeuralNetPrms& nnPrms) +// { +// shutdown(); + +// _genome = genome; +// _nnPrms = nnPrms; + +// _cppn.create(_genome); +// _neuralNet.create(_cppn, _nnPrms); + +// { +// float gridStep = 2.0f / 16.0f; +// Color gridClr = _uiColor; +// gridClr.a = 64; + +// for (float i = -1.0f; i <= 1.0f; i += gridStep) { +// _grid.append({{ -1.0f, i }, gridClr }); +// _grid.append({{ 1.0f, i }, gridClr }); +// _grid.append({{ i, -1.0f }, gridClr }); +// _grid.append({{ i, 1.0f }, gridClr }); +// } +// } + +// _executor = Thread([&]() { +// _running = true; + +// { +// VideoMode videoMode(RESOLUTION, RESOLUTION); +// String title("Cppn Explorer"); +// Uint32 style(Style::Titlebar | Style::Close); +// ContextSettings settings(0, 0, 8); +// View view(FloatRect(-1.0f, -1.0f, 2.0f, 2.0f)); + +// _window.create(videoMode, title, style, settings); +// _window.setVerticalSyncEnabled(true); +// _window.setView(view); +// } + +// _cppn.inputAt(5) = 1.0; + +// _valueImage.create(RESOLUTION, RESOLUTION); +// _biasImage.create(RESOLUTION, RESOLUTION); +// print(&WEIGHTS); +// print(&BIAS); + +// _valueSprite.setTexture(&_valueTexture); +// _valueSprite.setSize(Vector2f(2.0f, 2.0f)); +// _valueSprite.setOrigin(1.0f, 1.0f); +// _valueSprite.setPosition(0.0f, 0.0f); + +// _biasSprite.setTexture(&_biasTexture); +// _biasSprite.setSize(Vector2f(2.0f, 2.0f)); +// _biasSprite.setOrigin(1.0f, 1.0f); +// _biasSprite.setPosition(0.0f, 0.0f); + +// _cursorH.setFillColor(_uiColor); +// _cursorV.setFillColor(_uiColor); +// _cursorH.setOrigin(_cursorH.getSize() / 2.0f); +// _cursorV.setOrigin(_cursorV.getSize() / 2.0f); +// _cursorH.setOutlineThickness(PIXEL); +// _cursorV.setOutlineThickness(PIXEL); +// _cursorH.setOutlineColor({ 128, 128, 128 }); +// _cursorV.setOutlineColor({ 128, 128, 128 }); + +// _neurons.reserve(_neuralNet.getNeuronsCount()); + +// for (auto& i : _neuralNet.getNeurons()) { +// _neurons.emplace_back(); +// createNeuron(_neurons.back(), i); +// } + +// while (_running) { +// Event event; + +// while (_window.pollEvent(event)) { +// switch (event.type) { +// case Event::KeyPressed: +// switch (event.key.code) { +// case Keyboard::B: +// _showBias = !_showBias; +// break; + +// case Keyboard::C: +// placeCursorAt({ 0.0f, 0.0f }); +// print(_field); +// break; + +// case Keyboard::F: +// _field == &WEIGHTS ? ++_field : --_field; +// print(_field); +// break; + +// case Keyboard::V: +// _showField = !_showField; +// break; + +// case Keyboard::N: +// _showNeurons = !_showNeurons; +// break; + +// case Keyboard::G: +// _showGrid = !_showGrid; +// break; + +// default:; +// } + +// break; + +// case Event::MouseButtonPressed: +// if (event.mouseButton.button == Mouse::Left) { +// placeCursorAt(_window.mapPixelToCoords(Mouse::getPosition(_window))); +// print(_field); +// } + +// break; + +// case Event::Closed: +// _running = false; +// break; + +// default:; +// } +// } + +// _window.clear({ 8, 8, 16 }); + +// if (_showField) { +// if (_showBias) { +// _window.draw(_biasSprite); +// } else { +// _window.draw(_valueSprite); +// } +// } + +// if (_showGrid) { +// _window.draw(_grid, { BlendMode::BlendAdd }); +// } + +// if (_showNeurons) { +// for (auto& i : _neurons) { +// _window.draw(i._synapses); +// } + +// for (auto& i : _neurons) { +// if (i._type != Neuron::Type::HIDDEN) { +// continue; +// } + +// _window.draw(i._body); +// _window.draw(i._nucleus); +// } + +// for (auto& i : _neurons) { +// if (i._type == Neuron::Type::HIDDEN) { +// continue; +// } + +// _window.draw(i._body); +// _window.draw(i._nucleus); +// } +// } + +// _window.draw(_cursorH); +// _window.draw(_cursorV); + +// _window.display(); +// } +// }); +// } + +// void +// CppnExplorer::shutdown() +// { +// if (_executor.joinable()) { +// _running = false; +// _executor.join(); +// } + +// this->~CppnExplorer(); +// new (this) CppnExplorer(); +// } + +// void +// CppnExplorer::print(const Color* field) +// { +// size_t out = 0; +// double* x1 = nullptr; +// double* y1 = nullptr; +// double* x2 = nullptr; +// double* y2 = nullptr; +// Image* image = nullptr; +// Texture* texture = nullptr; + +// if (field == &WEIGHTS) { +// x1 = &_cppn.inputAt(0); +// y1 = &_cppn.inputAt(1); +// x2 = &_cppn.inputAt(2); +// y2 = &_cppn.inputAt(3); +// } else { +// x1 = &_cppn.inputAt(2); +// y1 = &_cppn.inputAt(3); +// x2 = &_cppn.inputAt(0); +// y2 = &_cppn.inputAt(1); +// } + +// *x1 = _cursorPos.x; +// *y1 = _cursorPos.y; + +// if (field == &BIAS) { +// out = 1; +// image = &_biasImage; +// texture = &_biasTexture; +// } else { +// image = &_valueImage; +// texture = &_valueTexture; +// } + +// double half = static_cast(RESOLUTION / 2); + +// for (unsigned y = 0; y < RESOLUTION; ++y) { +// for (unsigned x = 0; x < RESOLUTION; ++x) { +// *x2 = (static_cast(x) - half) / half; +// *y2 = (static_cast(y) - half) / half; +// _cppn.inputAt(4) = Point(*x1, *y1).distance(Point(*x2, *y2)); +// _cppn.cycle(); + +// auto multColor = [](const Color& base, double factor) { +// Color result; + +// result.r = static_cast(static_cast(base.r) * factor); +// result.g = static_cast(static_cast(base.g) * factor); +// result.b = static_cast(static_cast(base.b) * factor); + +// return result; +// }; + +// if (_cppn.outputAt(out) > 0) { +// image->setPixel(x, y, multColor(Color::White, _cppn.outputAt(out))); +// } else { +// image->setPixel(x, y, multColor(*field, fabs(_cppn.outputAt(out)))); +// } +// } +// } + +// texture->loadFromImage(*image); +// } + +// void +// CppnExplorer::placeCursorAt(const Vector2f& newPos) +// { +// _cursorPos = newPos; +// _cursorH.setPosition(_cursorPos); +// _cursorV.setPosition(_cursorPos); +// } + +// void +// CppnExplorer::createNeuron(Neuron& repNeuron, const NeuralNet::Neuron& srcNeuron) +// { +// repNeuron._body.setOutlineThickness(PIXEL * 2.0f); +// repNeuron._nucleus.setOutlineThickness(PIXEL * 2.0f); + +// float radius = 0.0f; +// Color inputColor = BIAS; +// Color hiddenColor = INV_WEIGHTS; +// Color outputColor = WEIGHTS; + +// inputColor.a = 128; +// hiddenColor.a = 128; +// outputColor.a = 128; + +// switch (srcNeuron._type) { +// case NeuralNet::Neuron::Type::INPUT: +// repNeuron._type = Neuron::Type::INPUT; +// repNeuron._body.setOutlineColor(inputColor); +// repNeuron._body.setFillColor({ 0, 0, 0, 200 }); +// radius = PIXEL * 24.0f; +// break; + +// case NeuralNet::Neuron::Type::HIDDEN: +// repNeuron._type = Neuron::Type::HIDDEN; +// repNeuron._body.setOutlineColor(hiddenColor); +// repNeuron._body.setFillColor({ 0, 0, 0, 200 }); + +// { +// float level = 1.0f; +// for (; srcNeuron._position._x * level != floor(srcNeuron._position._x * level); level *= 2.0f); +// radius = 1.0f / (level * 4.0f); + +// if (radius > PIXEL * 16.0f) { +// radius = PIXEL * 16.0f; +// } +// } + +// break; + +// case NeuralNet::Neuron::Type::OUTPUT: +// repNeuron._type = Neuron::Type::OUTPUT; +// repNeuron._body.setOutlineColor(outputColor); +// repNeuron._body.setFillColor({ 0, 0, 0, 200 }); +// radius = PIXEL * 24.0f; +// break; +// } + +// repNeuron._body.setRadius(radius); +// repNeuron._body.setOrigin(radius, radius); +// repNeuron._body.setPosition(srcNeuron._position._x, srcNeuron._position._y); + +// repNeuron._nucleus.setRadius(radius / 2.0f); +// repNeuron._nucleus.setOrigin(radius / 2.0f, radius / 2.0f); +// repNeuron._nucleus.setPosition(srcNeuron._position._x, srcNeuron._position._y); +// repNeuron._nucleus.setOutlineColor(repNeuron._body.getOutlineColor()); + +// double multInt = static_cast(fabs(srcNeuron._bias / 3.0) * 255.0); +// Color colorMult(multInt, multInt, multInt, 128); + +// if (srcNeuron._bias > 0) { +// repNeuron._nucleus.setFillColor(Color::White * colorMult); +// } else { +// repNeuron._nucleus.setFillColor(BIAS * colorMult); +// } + +// Color synColor = WEIGHTS; + +// for (auto& i : srcNeuron._synapses) { +// for (auto& j : _neuralNet.getNeurons()) { +// if (&j._output == i._input) { +// Uint8 weight = static_cast(i._weight * 20.0); +// Vector2f srcPos(j._position._x, j._position._y); + +// if (i._input == &srcNeuron._output) { +// Color selfSynColor; + +// if (i._weight > 0.0) { +// selfSynColor = Color(255, 255, 255, 20 + weight); +// } else { +// selfSynColor = synColor; +// } + +// float rad2 = repNeuron._body.getRadius() * 2.0f; +// Vector2f p1 = repNeuron._body.getPosition() + Vector2f(-rad2, -rad2); +// Vector2f p2 = repNeuron._body.getPosition() + Vector2f(-rad2, rad2); +// Vector2f p3 = repNeuron._body.getPosition() + Vector2f( rad2, rad2); +// Vector2f p4 = repNeuron._body.getPosition() + Vector2f( rad2, -rad2); + +// repNeuron._synapses.append({ p1, selfSynColor }); +// repNeuron._synapses.append({ p2, selfSynColor }); + +// repNeuron._synapses.append({ p2, selfSynColor }); +// repNeuron._synapses.append({ p3, selfSynColor }); + +// repNeuron._synapses.append({ p3, selfSynColor }); +// repNeuron._synapses.append({ p4, selfSynColor }); + +// repNeuron._synapses.append({ p4, selfSynColor }); +// repNeuron._synapses.append({ p1, selfSynColor }); +// } else { +// repNeuron._synapses.append({ repNeuron._body.getPosition(), Color::Black }); + +// if (i._weight > 0.0) { +// repNeuron._synapses.append({{ srcPos }, Color(255, 255, 255, 20 + weight) }); +// } else { +// synColor.a = 20 + weight; +// repNeuron._synapses.append({{ srcPos }, synColor }); +// } +// } + +// break; +// } +// } +// } +// } -- cgit v1.2.1