Exemplo n.º 1
0
void AggregateLibrary::addAggregate(AggregatePtr const& aggregate)
{
    if (!aggregate)
        throw SYSTEM_EXCEPTION(SCIDB_SE_INTERNAL, SCIDB_LE_CANT_ADD_NULL_FACTORY);

    //Try to find functions with 1 argument which can match new aggregate
    std::vector<TypeId> inputTypes(1, aggregate->getAggregateType().typeId());
    FunctionDescription functDescription;
    std::vector<FunctionPointer> converters;
    bool supportsVectorMode;
    bool foundScalar = false;

    foundScalar |= FunctionLibrary::getInstance()->findFunction(
            aggregate->getName(),
            inputTypes,
            functDescription,
            converters,
            supportsVectorMode,
            true);

    foundScalar |= FunctionLibrary::getInstance()->findFunction(
            aggregate->getName(),
            inputTypes,
            functDescription,
            converters,
            supportsVectorMode,
            false);

    if (foundScalar)
    {
        throw USER_EXCEPTION(SCIDB_SE_UDO, SCIDB_LE_CANNOT_ADD_AGGREGATE) << aggregate->getName();
    }

    const FactoriesMap::const_iterator i = _registeredFactories.find(aggregate->getName());
    if (i != _registeredFactories.end()) {
        const FactoriesMap::value_type::second_type::const_iterator i2 = i->second.find(aggregate->getAggregateType().typeId());
        if (i2 != i->second.end())
            throw SYSTEM_EXCEPTION(SCIDB_SE_INTERNAL, SCIDB_LE_DUPLICATE_AGGREGATE_FACTORY);
    }

    _registeredFactories[aggregate->getName()][aggregate->getAggregateType().typeId()] = aggregate;
}
Exemplo n.º 2
0
int main() {
	sf::RenderWindow window;

	sf::ContextSettings glContextSettings;
	glContextSettings.antialiasingLevel = 4;

	window.create(sf::VideoMode(800, 600), "BIDInet", sf::Style::Default, glContextSettings);

	window.setFramerateLimit(60);
	window.setVerticalSyncEnabled(true);

	std::mt19937 generator(time(nullptr));

	/*sys::ComputeSystem cs;

	cs.create(sys::ComputeSystem::_gpu);

	sys::ComputeProgram program;

	program.loadFromFile("resources/bidinet.cl", cs);

	bidi::BIDInet bidinet;

	std::vector<bidi::BIDInet::InputType> inputTypes(64, bidi::BIDInet::_state);

	const int numStates = 3 + 3 + 2 + 2 + 1 + 2 + 2;
	const int numActions = 3 + 3 + 2 + 2;
	const int numQ = 8;

	for (int i = 0; i < numStates; i++)
		inputTypes[i] = bidi::BIDInet::_state;

	for (int i = 0; i < numActions; i++)
		inputTypes[numStates + i] = bidi::BIDInet::_action;

	std::vector<bidi::BIDInet::LayerDesc> layerDescs(2);

	layerDescs[0]._fbRadius = 16;
	layerDescs[1]._width = 8;
	layerDescs[1]._height = 8;

	bidinet.createRandom(cs, program, 8, 8, inputTypes, layerDescs, -0.1f, 0.1f, 0.001f, 1.0f, generator);*/

	// Physics
	std::shared_ptr<b2World> world = std::make_shared<b2World>(b2Vec2(0.0f, -9.81f));

	const float pixelsPerMeter = 256.0f;

	const float groundWidth = 5000.0f;
	const float groundHeight = 5.0f;

	// Create ground
	b2BodyDef groundBodyDef;
	groundBodyDef.position.Set(0.0f, 0.0f);

	b2Body* groundBody = world->CreateBody(&groundBodyDef);

	b2PolygonShape groundBox;
	groundBox.SetAsBox(groundWidth * 0.5f, groundHeight * 0.5f);

	groundBody->CreateFixture(&groundBox, 0.0f);

	sf::Texture skyTexture;

	skyTexture.loadFromFile("resources/background1.png");

	skyTexture.setSmooth(true);

	sf::Texture floorTexture;
	
	floorTexture.loadFromFile("resources/floor1.png");

	floorTexture.setRepeated(true);
	floorTexture.setSmooth(true);

	Runner runner0;

	runner0.createDefault(world, b2Vec2(0.0f, 2.762f), 0.0f, 1);

	//Runner runner1;

	//runner1.createDefault(world, b2Vec2(0.0f, 2.762f), 0.0f, 2);

	//deep::FERL ferl;

	const int recCount = 4;
	const int clockCount = 4;

	//ferl.createRandom(3 + 3 + 2 + 2 + 1 + 2 + 2 + recCount + clockCount, 3 + 3 + 2 + 2 + recCount, 32, 0.01f, generator);

	//std::vector<float> prevAction(ferl.getNumAction(), 0.0f);

	deep::CSRL prsdr;

	const int inputCount = 3 + 3 + 2 + 2 + 1 + 2 + 2 + recCount + clockCount + 1;
	const int outputCount = 3 + 3 + 2 + 2 + recCount;

	std::vector<deep::CSRL::LayerDesc> layerDescs(2);

	layerDescs[0]._width = 8;
	layerDescs[0]._height = 8;

	layerDescs[1]._width = 4;
	layerDescs[1]._height = 4;

	std::vector<sdr::IPRSDRRL::InputType> inputTypes(7 * 7, sdr::IPRSDRRL::_state);

	prsdr.createRandom(7, 7, 8, layerDescs, -0.01f, 0.01f, 0.5f, generator);

	//deep::SDRRL sdrrl;

	//sdrrl.createRandom(inputCount, outputCount, 32, -0.01f, 0.01f, 0.0f, generator);

	// ---------------------------- Game Loop -----------------------------

	sf::View view = window.getDefaultView();

	bool quit = false;

	sf::Clock clock;

	float dt = 0.017f;

	int steps = 0;

	do {
		clock.restart();

		// ----------------------------- Input -----------------------------

		sf::Event windowEvent;

		while (window.pollEvent(windowEvent))
		{
			switch (windowEvent.type)
			{
			case sf::Event::Closed:
				quit = true;
				break;
			}
		}

		if (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))
			quit = true;

		//bidinet.simStep(cs, 0.0f, 0.98f, 0.001f, 0.95f, 0.01f, 0.01f, generator);

		const float maxRunnerBodyAngle = 0.3f;
		const float runnerBodyAngleStab = 10.0f;

		{
			float reward;
			
			if (sf::Keyboard::isKeyPressed(sf::Keyboard::K))
				reward = -runner0._pBody->GetLinearVelocity().x;
			else
				reward = runner0._pBody->GetLinearVelocity().x;

			std::vector<float> state;

			runner0.getStateVector(state);

			std::vector<float> action(3 + 3 + 2 + 2 + recCount);

			for (int a = 0; a < recCount; a++)
				state.push_back(prsdr.getPrediction(inputCount + outputCount - recCount + a));

			for (int a = 0; a < clockCount; a++)
				state.push_back(std::sin(steps / 60.0f * 2.0f * a * 2.0f * 3.141596f));

			for (int i = 0; i < state.size(); i++)
				prsdr.setInput(i, state[i]);

			//sdrrl.simStep(reward, 0.1f, 0.99f, 16, 0.01f, 0.01f, 0.01f, 0.01f, 16, 0.05f, 0.98f, 0.05f, 0.01f, 0.01f, 4.0f, generator);
			prsdr.simStep(reward, generator);

			for (int i = 0; i < action.size(); i++)
				action[i] = prsdr.getPrediction(inputCount + i) * 0.5f + 0.5f;

			runner0.motorUpdate(action, 12.0f);

			// Keep upright
			if (std::abs(runner0._pBody->GetAngle()) > maxRunnerBodyAngle)
				runner0._pBody->SetAngularVelocity(-runnerBodyAngleStab * runner0._pBody->GetAngle());
		}

		/*{
			float reward;

			if (sf::Keyboard::isKeyPressed(sf::Keyboard::K))
				reward = -runner1._pBody->GetLinearVelocity().x;
			else
				reward = runner1._pBody->GetLinearVelocity().x;

			std::vector<float> state;

			runner1.getStateVector(state);

			std::vector<float> action(3 + 3 + 2 + 2 + recCount);

			for (int a = 0; a < recCount; a++)
				state.push_back(prevAction[prevAction.size() - recCount + a]);

			for (int a = 0; a < clockCount; a++)
				state.push_back(std::sin(steps / 60.0f * 2.0f * a * 2.0f * 3.141596f));

			// Bias
			state.push_back(1.0f);

			//ferl.step(state, action, reward, 0.5f, 0.99f, 0.98f, 0.05f, 16, 4, 0.05f, 0.01f, 0.05f, 600, 64, 0.01f, generator);

			for (int i = 0; i < action.size(); i++)
				action[i] = action[i] * 0.5f + 0.5f;

			prevAction = action;

			runner1.motorUpdate(action, 12.0f);

			// Keep upright
			if (std::abs(runner1._pBody->GetAngle()) > maxRunnerBodyAngle)
				runner1._pBody->SetAngularVelocity(-runnerBodyAngleStab * runner1._pBody->GetAngle());
		}*/

		int subSteps = 1;

		for (int ss = 0; ss < subSteps; ss++) {
			world->ClearForces();

			world->Step(1.0f / 60.0f / subSteps, 64, 64);
		}

		if (!sf::Keyboard::isKeyPressed(sf::Keyboard::T) || steps % 200 == 1) {
			// -------------------------------------------------------------------

			//if (!sf::Keyboard::isKeyPressed(sf::Keyboard::B))
			//	view.setCenter(runner1._pBody->GetPosition().x * pixelsPerMeter, -runner1._pBody->GetPosition().y * pixelsPerMeter);
			//else
				view.setCenter(runner0._pBody->GetPosition().x * pixelsPerMeter, -runner0._pBody->GetPosition().y * pixelsPerMeter);

			// Draw sky
			sf::Sprite skySprite;
			skySprite.setTexture(skyTexture);

			window.setView(window.getDefaultView());

			window.draw(skySprite);

			window.setView(view);

			sf::RectangleShape floorShape;
			floorShape.setSize(sf::Vector2f(groundWidth * pixelsPerMeter, groundHeight * pixelsPerMeter));
			floorShape.setTexture(&floorTexture);
			floorShape.setTextureRect(sf::IntRect(0, 0, groundWidth * pixelsPerMeter, groundHeight * pixelsPerMeter));

			floorShape.setOrigin(sf::Vector2f(groundWidth * pixelsPerMeter * 0.5f, groundHeight * pixelsPerMeter * 0.5f));

			window.draw(floorShape);

			//runner1.renderDefault(window, sf::Color::Blue, pixelsPerMeter);
			runner0.renderDefault(window, sf::Color::Red, pixelsPerMeter);

			/*sf::Image img;
			img.create(sdrrl.getNumCells(), 1);

			for (int i = 0; i < sdrrl.getNumCells(); i++) {
				sf::Color c = sf::Color::Black;

				c.r = c.g = c.b = 255.0f * (sdrrl.getCellState(i) > 0.0f ? 1.0f : 0.0f);

				img.setPixel(i, 0, c);
			}

			float scale = 4.0f;

			sf::Texture tex;
			tex.loadFromImage(img);

			sf::Sprite s;
			s.setTexture(tex);

			s.setScale(sf::Vector2f(scale, scale));

			s.setPosition(sf::Vector2f(0.0f, window.getSize().y - scale * img.getSize().y));

			window.setView(window.getDefaultView());

			window.draw(s);*/

			window.setView(view);

			window.display();
		}
		else {
			if (steps % 100 == 0)
				std::cout << "Steps: " << steps << " Distance: " << runner0._pBody->GetPosition().x << std::endl;
		}

		//dt = clock.getElapsedTime().asSeconds();

		steps++;

	} while (!quit);

	world->DestroyBody(groundBody);

	return 0;
}
Exemplo n.º 3
0
int main() {
	std::mt19937 generator(time(nullptr));

	_ballPosition = sf::Vector2f(0.5f, 0.5f);
	_ballVelocity = sf::Vector2f(0.44f, 0.55f);

	_ballVelocity *= ballSpeed / std::sqrt(_ballVelocity.x * _ballVelocity.x + _ballVelocity.y * _ballVelocity.y);

	_paddlePosition = 0.5f;

	std::uniform_real_distribution<float> dist01(0.0f, 1.0f);

	sf::RenderWindow window;

	window.create(sf::VideoMode(800, 800), "BIDInet", sf::Style::Default);

	window.setFramerateLimit(60);
	window.setVerticalSyncEnabled(true);

	sf::RenderTexture visionRT;

	visionRT.create(16, 16);

	deep::CSRL agent;

	std::vector<deep::CSRL::LayerDesc> layerDescs(3);

	layerDescs[0]._width = 6;
	layerDescs[0]._height = 6;

	layerDescs[1]._width = 5;
	layerDescs[1]._height = 5;

	layerDescs[2]._width = 4;
	layerDescs[2]._height = 4;

	int inWidth = 16;
	int inHeight = 18;

	std::vector<deep::CSRL::InputType> inputTypes(inWidth * inHeight, deep::CSRL::_state);

	for (int i = 0; i < inWidth; i++) {
		inputTypes[i + (inHeight - 2) * inWidth] = deep::CSRL::_action;
		inputTypes[i + (inHeight - 1) * inWidth] = deep::CSRL::_q;
	}

	agent.createRandom(inWidth, inHeight, 8, inputTypes, layerDescs, -0.01f, 0.01f, 0.01f, 0.05f, 0.2f, generator);

	// ---------------------------- Game Loop -----------------------------

	bool quit = false;

	sf::Clock clock;

	float dt = 0.017f;

	float averageReward = 0.0f;
	const float averageRewardDecay = 0.003f;

	int steps = 0;

	do {
		clock.restart();

		// ----------------------------- Input -----------------------------

		sf::Event windowEvent;

		while (window.pollEvent(windowEvent))
		{
			switch (windowEvent.type)
			{
			case sf::Event::Closed:
				quit = true;
				break;
			}
		}

		if (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))
			quit = true;

		visionRT.clear();

		renderScene(visionRT);

		visionRT.display();

		sf::Image img = visionRT.getTexture().copyToImage();

		for (int x = 0; x < img.getSize().x; x++)
			for (int y = 0; y < img.getSize().y; y++) {
				sf::Color c = img.getPixel(x, y);

				/*float valR = 0.0f;
				float valG = 0.0f;

				if (c.r > 0)
				valR = 1.0f;

				if (c.g > 0)
				valG = 1.0f;

				swarm.setState(x, y, 0, valR);
				swarm.setState(x, y, 1, valG);*/

				float val = 0.0f;

				if (c.r > 0)
					val = 0.5f;

				if (c.g > 0)
					val = 1.0f;

				agent.setInput(x, y, val);
			}

		float reward = 0.0f;

		if (_ballPosition.x < 0.0f) {
			_ballPosition.x = 0.0f;

			_ballVelocity.x *= -1.0f;
		}

		if (_ballPosition.y < 0.0f) {
			_ballPosition.y = 0.0f;

			_ballVelocity.y *= -1.0f;
		}

		if (_ballPosition.x > 1.0f) {
			_ballPosition.x = 1.0f;

			_ballVelocity.x *= -1.0f;
		}

		if (_ballPosition.y > 1.0f - bottomRatio) {
			_ballPosition.y = 1.0f - bottomRatio;

			if (_ballPosition.x > _paddlePosition - paddleWidthRatio && _ballPosition.x < _paddlePosition + paddleWidthRatio) {
				reward += 10.0f;
			}
			else
				reward -= 5.0f;

			_ballVelocity.y *= -1.0f;
		}

		_ballPosition += _ballVelocity;

		averageReward = (1.0f - averageRewardDecay) * averageReward + averageRewardDecay * reward;

		agent.simStep(reward, generator);

		float act = 0.0f;

		for (int i = 4; i < 5; i++) {
			act += agent.getPrediction(i, 16);
		}

		_paddlePosition = std::min(1.0f, std::max(0.0f, _paddlePosition + 0.1f * std::min(1.0f, std::max(-1.0f, act))));

		//std::cout << averageReward << std::endl;

		if (!sf::Keyboard::isKeyPressed(sf::Keyboard::T)) {
			window.clear();

			renderScene(window);

			sf::Sprite vis;

			vis.setTexture(visionRT.getTexture());

			vis.setScale(4.0f, 4.0f);

			window.draw(vis);

			sf::Image predImg;

			predImg.create(16, 17);

			for (int x = 0; x < 16; x++)
				for (int y = 0; y < 17; y++) {
					sf::Color c = sf::Color::White;

					c.r = c.g = c.b = 255.0f * std::min(1.0f, std::max(0.0f, agent.getPrediction(x, y)));

					predImg.setPixel(x, y, c);
				}

			sf::Texture t;
			t.loadFromImage(predImg);

			sf::Sprite s;

			s.setTexture(t);

			s.setScale(4.0f, 4.0f);

			s.setPosition(4.0f * 16.0f, 0.0f);

			window.draw(s);

			window.display();
		}

		if (steps % 100 == 0)
			std::cout << "Steps: " << steps << " Average Reward: " << averageReward << std::endl;

		//dt = clock.getElapsedTime().asSeconds();

		steps++;

	} while (!quit);

	return 0;
}
Exemplo n.º 4
0
int main() {
	std::mt19937 generator(time(nullptr));

	sf::RenderWindow renderWindow;

	renderWindow.create(sf::VideoMode(1280, 720), "Reinforcement Learning", sf::Style::Default);

	renderWindow.setVerticalSyncEnabled(true);
	renderWindow.setFramerateLimit(60);

	// ---------------------------------- RL Init ------------------------------------

	/*sc::HTSLPVLV agentBlue;
	sc::HTSLPVLV agentRed;

	std::vector<sc::HTSLPVLV::InputType> inputTypes(20);

	for (int i = 0; i < 12; i++)
		inputTypes[i] = sc::HTSLPVLV::_state;
	
	for (int i = 12; i < 14; i++)
		inputTypes[i] = sc::HTSLPVLV::_action;

	for (int i = 14; i < 16; i++)
		inputTypes[i] = sc::HTSLPVLV::_pv;

	for (int i = 16; i < 18; i++)
		inputTypes[i] = sc::HTSLPVLV::_lve;

	for (int i = 18; i < 20; i++)
		inputTypes[i] = sc::HTSLPVLV::_lvi;

	std::vector<sc::HTSL::LayerDesc> layerDescs(2);

	layerDescs[0]._width = 20;
	layerDescs[0]._height = 20;

	layerDescs[1]._width = 12;
	layerDescs[1]._height = 12;

	//layerDescs[2]._width = 8;
	//layerDescs[2]._height = 8;

	agentBlue.createRandom(5, 4, 8, inputTypes, layerDescs, generator);
	agentRed.createRandom(5, 4, 8, inputTypes, layerDescs, generator);*/

	float rewardTimer = 0.0f;
	float rewardTime = 0.25f;
	float lastReward = 0.5f;

	//sc::HTSLSARSA agentBlue;
	sc::HTSLSARSA agentRed;

	std::vector<sc::HTSLSARSA::InputType> inputTypes(16);

	for (int i = 0; i < 12; i++)
		inputTypes[i] = sc::HTSLSARSA::_state;

	for (int i = 12; i < 14; i++)
		inputTypes[i] = sc::HTSLSARSA::_action;

	for (int i = 14; i < 16; i++)
		inputTypes[i] = sc::HTSLSARSA::_q;

	std::vector<sc::HTSL::LayerDesc> layerDescs(3);

	layerDescs[0]._width = 28;
	layerDescs[0]._height = 28;

	layerDescs[1]._width = 18;
	layerDescs[1]._height = 18;

	layerDescs[2]._width = 12;
	layerDescs[2]._height = 12;

	//agentBlue.createRandom(4, 4, 8, inputTypes, layerDescs, generator);
	agentRed.createRandom(4, 4, 8, inputTypes, layerDescs, generator);

	//deep::FERL agentBlue;
	//agentBlue.createRandom(12, 2, 32, 0.01f, generator);

	//deep::FERL agentRed;
	//agentRed.createRandom(12, 2, 32, 0.01f, generator);

	// --------------------------------- Game Init -----------------------------------

	const float slimeRadius = 94.5f;
	const float ballRadius = 23.5f;
	const float wallRadius = 22.5f;
	const float fieldRadius = 640.0f;

	const float gravity = 900.0f;
	const float slimeBounce = 100.0f;
	const float wallBounceDecay = 0.8f;
	const float slimeJump = 500.0f;
	const float maxSlimeSpeed = 1000.0f;
	const float slimeMoveAccel = 5000.0f;
	const float slimeMoveDeccel = 8.0f;

	std::uniform_real_distribution<float> dist01(0.0f, 1.0f);

	sf::Vector2f fieldCenter = sf::Vector2f(renderWindow.getSize().x * 0.5f, renderWindow.getSize().y * 0.5f + 254.0f);
	sf::Vector2f wallCenter = fieldCenter + sf::Vector2f(0.0f, -182.0f);

	PhyObj blue;
	PhyObj red;
	PhyObj ball;

	blue._position = fieldCenter + sf::Vector2f(-200.0f, 0.0f);
	blue._velocity = sf::Vector2f(0.0f, 0.0f);
	red._position = fieldCenter + sf::Vector2f(200.0f, 0.0f);
	red._velocity = sf::Vector2f(0.0f, 0.0f);
	ball._position = fieldCenter + sf::Vector2f(2.0f, -300.0f);
	ball._velocity = sf::Vector2f((dist01(generator)) * 600.0f, -(dist01(generator)) * 500.0f);

	sf::Texture backgroundTexture;
	backgroundTexture.loadFromFile("resources/slimevolleyball/background.png");

	sf::Texture blueSlimeTexture;
	blueSlimeTexture.loadFromFile("resources/slimevolleyball/slimeBodyBlue.png");

	sf::Texture redSlimeTexture;
	redSlimeTexture.loadFromFile("resources/slimevolleyball/slimeBodyRed.png");

	sf::Texture ballTexture;
	ballTexture.loadFromFile("resources/slimevolleyball/ball.png");

	sf::Texture eyeTexture;
	eyeTexture.loadFromFile("resources/slimevolleyball/slimeEye.png");
	eyeTexture.setSmooth(true);

	sf::Texture arrowTexture;
	arrowTexture.loadFromFile("resources/slimevolleyball/arrow.png");

	sf::Font scoreFont;
	scoreFont.loadFromFile("resources/slimevolleyball/scoreFont.ttf");

	int scoreRed = 0;
	int scoreBlue = 0;

	int prevScoreRed = 0;
	int prevScoreBlue = 0;

	float prevBallX = fieldCenter.x;

	// ------------------------------- Simulation Loop -------------------------------

	bool noRender = false;
	bool prevPressK = false;

	bool quit = false;

	float dt = 0.017f;

	do {
		sf::Event event;

		while (renderWindow.pollEvent(event)) {
			switch (event.type) {
			case sf::Event::Closed:
				quit = true;
				break;
			}
		}

		if (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))
			quit = true;

		// ---------------------------------- Physics ----------------------------------

		bool blueBounced = false;
		bool redBounced = false;

		// Ball
		{
			ball._velocity.y += gravity * dt;
			ball._position += ball._velocity * dt;

			// To floor (game restart)
			if (ball._position.y + ballRadius > fieldCenter.y) {
				if (ball._position.x < fieldCenter.x)
					scoreRed++;
				else
					scoreBlue++;

				blue._position = fieldCenter + sf::Vector2f(-200.0f, 0.0f);
				blue._velocity = sf::Vector2f(0.0f, 0.0f);
				red._position = fieldCenter + sf::Vector2f(200.0f, 0.0f);
				red._velocity = sf::Vector2f(0.0f, 0.0f);
				ball._position = fieldCenter + sf::Vector2f(2.0f, -300.0f);
				ball._velocity = sf::Vector2f((dist01(generator)) * 600.0f, -(dist01(generator)) * 500.0f);
			}

			// To wall
			if (((ball._position.x + ballRadius) > (wallCenter.x - wallRadius) && ball._position.x < wallCenter.x) || ((ball._position.x - ballRadius) < (wallCenter.x + wallRadius) && ball._position.x > wallCenter.x)) {
				// If above rounded part
				if (ball._position.y < wallCenter.y) {
					sf::Vector2f delta = ball._position - wallCenter;

					float dist = std::sqrt(delta.x * delta.x + delta.y * delta.y);

					if (dist < wallRadius + ballRadius) {
						sf::Vector2f normal = delta / dist;

						// Reflect velocity
						sf::Vector2f reflectedVelocity = ball._velocity - 2.0f * (ball._velocity.x * normal.x + ball._velocity.y * normal.y) * normal;

						ball._velocity = reflectedVelocity * wallBounceDecay;

						ball._position = wallCenter + normal * (wallRadius + ballRadius);
					}
				}
				else {
					// If on left side
					if (ball._position.x < wallCenter.x) {
						ball._velocity.x = wallBounceDecay * -ball._velocity.x;
						ball._position.x = wallCenter.x - wallRadius - ballRadius;
					}
					else {
						ball._velocity.x = wallBounceDecay * -ball._velocity.x;
						ball._position.x = wallCenter.x + wallRadius + ballRadius;
					}
				}
			}

			// To blue slime			
			{
				sf::Vector2f delta = ball._position - blue._position;

				float dist = std::sqrt(delta.x * delta.x + delta.y * delta.y);

				if (dist < slimeRadius + ballRadius) {
					sf::Vector2f normal = delta / dist;

					// Reflect velocity
					sf::Vector2f reflectedVelocity = ball._velocity - 2.0f * (ball._velocity.x * normal.x + ball._velocity.y * normal.y) * normal;

					float magnitude = std::sqrt(reflectedVelocity.x * reflectedVelocity.x + reflectedVelocity.y * reflectedVelocity.y);

					sf::Vector2f normalizedReflected = reflectedVelocity / magnitude;

					ball._velocity = blue._velocity + (magnitude > slimeBounce ? reflectedVelocity : normalizedReflected * slimeBounce);

					ball._position = blue._position + normal * (wallRadius + slimeRadius);

					blueBounced = true;
				}
			}

			// To red slime			
			{
				sf::Vector2f delta = ball._position - red._position;

				float dist = std::sqrt(delta.x * delta.x + delta.y * delta.y);

				if (dist < slimeRadius + ballRadius) {
					sf::Vector2f normal = delta / dist;

					// Reflect velocity
					sf::Vector2f reflectedVelocity = ball._velocity - 2.0f * (ball._velocity.x * normal.x + ball._velocity.y * normal.y) * normal;

					float magnitude = std::sqrt(reflectedVelocity.x * reflectedVelocity.x + reflectedVelocity.y * reflectedVelocity.y);

					sf::Vector2f normalizedReflected = reflectedVelocity / magnitude;

					ball._velocity = red._velocity + (magnitude > slimeBounce ? reflectedVelocity : normalizedReflected * slimeBounce);

					ball._position = red._position + normal * (wallRadius + slimeRadius);

					redBounced = true;
				}
			}

			// Out of field, left and right
			{
				if (ball._position.x - ballRadius < fieldCenter.x - fieldRadius) {
					ball._velocity.x = wallBounceDecay * -ball._velocity.x;
					ball._position.x = fieldCenter.x - fieldRadius + ballRadius;
				}
				else if (ball._position.x + ballRadius > fieldCenter.x + fieldRadius) {
					ball._velocity.x = wallBounceDecay * -ball._velocity.x;
					ball._position.x = fieldCenter.x + fieldRadius - ballRadius;
				}
			}
		}

		// Blue slime
		{		
			blue._velocity.y += gravity * dt;
			blue._velocity.x += -slimeMoveDeccel * blue._velocity.x * dt;
			blue._position += blue._velocity * dt;

			if (sf::Keyboard::isKeyPressed(sf::Keyboard::A)) {
				blue._velocity.x += -slimeMoveAccel * dt;

				if (blue._velocity.x < -maxSlimeSpeed)
					blue._velocity.x = -maxSlimeSpeed;
			}
			else if (sf::Keyboard::isKeyPressed(sf::Keyboard::D)) {
				blue._velocity.x += slimeMoveAccel * dt;

				if (blue._velocity.x > maxSlimeSpeed)
					blue._velocity.x = maxSlimeSpeed;
			}

			if (blue._position.y > fieldCenter.y) {
				blue._velocity.y = 0.0f;
				blue._position.y = fieldCenter.y;
				
				if (sf::Keyboard::isKeyPressed(sf::Keyboard::W))
					blue._velocity.y -= slimeJump;
			}

			if (blue._position.x - slimeRadius < fieldCenter.x - fieldRadius) {
				blue._velocity.x = 0.0f;
				blue._position.x = fieldCenter.x - fieldRadius + slimeRadius;
			}

			if (blue._position.x + slimeRadius > wallCenter.x - wallRadius) {
				blue._velocity.x = 0.0f;
				blue._position.x = wallCenter.x - wallRadius - slimeRadius;
			}
		}

		// Blue slime
		/*{
			const float scalar = 0.001f;
			// Percepts
			std::vector<float> inputs(12);

			int index = 0;

			inputs[index++] = (ball._position.x - blue._position.x) * scalar;
			inputs[index++] = (ball._position.y - blue._position.y) * scalar;
			inputs[index++] = ball._velocity.x * scalar;
			inputs[index++] = ball._velocity.y * scalar;
			inputs[index++] = (red._position.x - blue._position.x) * scalar;
			inputs[index++] = (red._position.y - blue._position.y) * scalar;
			inputs[index++] = red._velocity.x * scalar;
			inputs[index++] = red._velocity.y * scalar;
			inputs[index++] = blue._position.x * scalar;
			inputs[index++] = blue._position.y * scalar;
			inputs[index++] = blue._velocity.x * scalar;
			inputs[index++] = blue._velocity.y * scalar;

			std::vector<float> outputs(2);

			// Actions
			for (int i = 0; i < 12; i++)
				agentBlue.setState(i, inputs[i]);

			float reward = (ball._position.x > fieldCenter.x && prevBallX < fieldCenter.x ? 1.0f : 0.5f) * 0.5f + (scoreRed > prevScoreRed ? 0.0f : 0.5f) * 0.5f;

			if (reward != 0.5f) {
				lastReward = reward = reward > 0.5f ? 1.0f : 0.0f;
				rewardTimer = 0.0f;
			}
			else if (rewardTimer < rewardTime) {
				reward = lastReward;

				rewardTimer += dt;
			}

			if (blueBounced)
				reward = std::max(reward, 0.55f);

			reward = (reward * 2.0f - 1.0f) * 0.01f - std::abs(ball._position.x - blue._position.x) * 0.001f;

			//reward = (scoreBlue - prevScoreBlue) - (scoreRed - prevScoreRed) - std::abs(ball._position.x - blue._position.x) * 0.001f;

			agentBlue.update(reward, generator);

			float move = agentBlue.getActionFromNodeIndex(0) * 2.0f - 1.0f;
			bool jump = agentBlue.getActionFromNodeIndex(1) > 0.5f;

			//std::vector<float> action(2);
			//agentBlue.step(inputs, action, reward, 0.01f, 0.995f, 0.99f, 10.0f, 64, 3, 0.02f, 0.04f, 0.04f, 800, 200, 0.003f, 0.0f, generator);

			//float move = action[0];
			//bool jump = action[1] > 0.0f;

			blue._velocity.y += gravity * dt;
			blue._velocity.x += -slimeMoveDeccel * blue._velocity.x * dt;
			blue._position += blue._velocity * dt;

			{
				blue._velocity.x += move * slimeMoveAccel * dt;

				if (blue._velocity.x < -maxSlimeSpeed)
					blue._velocity.x = -maxSlimeSpeed;
				else if (blue._velocity.x > maxSlimeSpeed)
					blue._velocity.x = maxSlimeSpeed;
			}

			if (blue._position.y > fieldCenter.y) {
				blue._velocity.y = 0.0f;
				blue._position.y = fieldCenter.y;

				if (jump)
					blue._velocity.y -= slimeJump;
			}

			if (blue._position.x - slimeRadius < fieldCenter.x - fieldRadius) {
				blue._velocity.x = 0.0f;
				blue._position.x = fieldCenter.x - fieldRadius + slimeRadius;
			}

			if (blue._position.x + slimeRadius > wallCenter.x - wallRadius) {
				blue._velocity.x = 0.0f;
				blue._position.x = wallCenter.x - wallRadius - slimeRadius;
			}
		}*/

		// Red slime
		{
			const float scalar = 0.001f;
			// Percepts
			std::vector<float> inputs(12);

			int index = 0;

			inputs[index++] = (ball._position.x - red._position.x) * scalar;
			inputs[index++] = (ball._position.y - red._position.y) * scalar;
			inputs[index++] = ball._velocity.x * scalar;
			inputs[index++] = ball._velocity.y * scalar;
			inputs[index++] = (blue._position.x - red._position.x) * scalar;
			inputs[index++] = (blue._position.y - red._position.y) * scalar;
			inputs[index++] = red._velocity.x * scalar;
			inputs[index++] = red._velocity.y * scalar;
			inputs[index++] = blue._position.x * scalar;
			inputs[index++] = blue._position.y * scalar;
			inputs[index++] = blue._velocity.x * scalar;
			inputs[index++] = blue._velocity.y * scalar;

			//std::vector<float> outputs(2);

			// Actions
			for (int i = 0; i < 12; i++)
				agentRed.setState(i, inputs[i]);

			float reward = (ball._position.x < fieldCenter.x && prevBallX >= fieldCenter.x ? 1.0f : 0.5f);
			
			if (reward != 0.5f) {
				lastReward = reward = reward > 0.5f ? 1.0f : 0.0f;
				rewardTimer = 0.0f;
			}
			else if (rewardTimer < rewardTime) {
				reward = lastReward;

				rewardTimer += dt;
			}

			if (redBounced)
				reward = std::max(reward, 0.55f);

			reward = (reward * 2.0f - 1.0f) * 0.1f - std::abs(ball._position.x - red._position.x) * 0.008f;

			//reward *= 0.05f;

			//reward = (scoreRed - prevScoreRed) - (scoreBlue - prevScoreBlue) - std::abs(ball._position.x - red._position.x) * 0.001f;

			//std::cout << "Reward: " << reward << std::endl;

			//agentRed.update(reward, generator);
			agentRed.update(reward, generator);
			//std::vector<float> action(2);
			//agentRed.step(inputs, action, reward, 0.01f, 0.995f, 0.99f, 10.0f, 32, 6, 0.05f, 0.04f, 0.04f, 800, 200, 0.003f, 0.0f, generator);

			//float move = action[0];
			//bool jump = action[1] > 0.0f;

			float move = agentRed.getActionFromNodeIndex(0) * 2.0f - 1.0f;
			bool jump = agentRed.getActionFromNodeIndex(1) > 0.5f;

			red._velocity.y += gravity * dt;
			red._velocity.x += -slimeMoveDeccel * red._velocity.x * dt;
			red._position += red._velocity * dt;

			{
				red._velocity.x += move * slimeMoveAccel * dt;

				if (red._velocity.x < -maxSlimeSpeed)
					red._velocity.x = -maxSlimeSpeed;
				else if (red._velocity.x > maxSlimeSpeed)
					red._velocity.x = maxSlimeSpeed;
			}
			
			if (red._position.y > fieldCenter.y) {
				red._velocity.y = 0.0f;
				red._position.y = fieldCenter.y;

				if (jump)
					red._velocity.y -= slimeJump;
			}

			if (red._position.x + slimeRadius > fieldCenter.x + fieldRadius) {
				red._velocity.x = 0.0f;
				red._position.x = fieldCenter.x + fieldRadius - slimeRadius;
			}

			if (red._position.x - slimeRadius < wallCenter.x + wallRadius) {
				red._velocity.x = 0.0f;
				red._position.x = wallCenter.x + wallRadius + slimeRadius;
			}
		}

		prevScoreRed = scoreRed;
		prevScoreBlue = scoreBlue;
		prevBallX = ball._position.x;

		if (sf::Keyboard::isKeyPressed(sf::Keyboard::K) && !prevPressK) {
			noRender = !noRender;
		}

		prevPressK = sf::Keyboard::isKeyPressed(sf::Keyboard::K);

		if (noRender)
			continue;

		// --------------------------------- Rendering ---------------------------------

		renderWindow.clear();

		{
			sf::Sprite s;
			s.setTexture(backgroundTexture);
			s.setOrigin(backgroundTexture.getSize().x * 0.5f, backgroundTexture.getSize().y * 0.5f);
			s.setPosition(renderWindow.getSize().x * 0.5f, renderWindow.getSize().y * 0.5f);

			renderWindow.draw(s);
		}

		{
			sf::Sprite s;
			s.setTexture(blueSlimeTexture);
			s.setOrigin(blueSlimeTexture.getSize().x * 0.5f, blueSlimeTexture.getSize().y);
			s.setPosition(blue._position);

			renderWindow.draw(s);
		}

		{
			sf::Sprite s;
			s.setTexture(eyeTexture);
			s.setOrigin(eyeTexture.getSize().x * 0.5f, eyeTexture.getSize().y * 0.5f);
			s.setPosition(blue._position + sf::Vector2f(50.0f, -28.0f));

			sf::Vector2f delta = ball._position - s.getPosition();

			float angle = std::atan2(delta.y, delta.x);

			s.setRotation(angle * 180.0f / 3.141596f);

			renderWindow.draw(s);
		}

		{
			sf::Sprite s;
			s.setTexture(redSlimeTexture);
			s.setOrigin(redSlimeTexture.getSize().x * 0.5f, redSlimeTexture.getSize().y);
			s.setPosition(red._position);

			renderWindow.draw(s);
		}

		{
			sf::Sprite s;
			s.setTexture(eyeTexture);
			s.setOrigin(eyeTexture.getSize().x * 0.5f, eyeTexture.getSize().y * 0.5f);
			s.setPosition(red._position + sf::Vector2f(-50.0f, -28.0f));

			sf::Vector2f delta = ball._position - s.getPosition();

			float angle = std::atan2(delta.y, delta.x);

			s.setRotation(angle * 180.0f / 3.141596f);

			renderWindow.draw(s);
		}

		{
			sf::Sprite s;
			s.setTexture(ballTexture);
			s.setOrigin(ballTexture.getSize().x * 0.5f, ballTexture.getSize().y * 0.5f);
			s.setPosition(ball._position);

			renderWindow.draw(s);
		}

		if (ball._position.y + ballRadius < 0.0f) {
			sf::Sprite s;
			s.setTexture(arrowTexture);
			s.setOrigin(arrowTexture.getSize().x * 0.5f, 0.0f);
			s.setPosition(ball._position.x, 0.0f);

			renderWindow.draw(s);
		}

		{
			sf::Text scoreText;
			scoreText.setFont(scoreFont);
			scoreText.setString(std::to_string(scoreBlue));
			scoreText.setCharacterSize(100);

			float width = scoreText.getLocalBounds().width;

			scoreText.setPosition(fieldCenter.x - width * 0.5f - 100.0f, 10.0f);
			
			scoreText.setColor(sf::Color(100, 133, 255));

			renderWindow.draw(scoreText);
		}

		{
			sf::Text scoreText;
			scoreText.setFont(scoreFont);
			scoreText.setString(std::to_string(scoreRed));
			scoreText.setCharacterSize(100);

			float width = scoreText.getLocalBounds().width;

			scoreText.setPosition(fieldCenter.x - width * 0.5f + 100.0f, 10.0f);

			scoreText.setColor(sf::Color(255, 100, 100));
			
			renderWindow.draw(scoreText);
		}

		if (sf::Keyboard::isKeyPressed(sf::Keyboard::P)) {
			float scale = 4.0f;

			float alignment = 0.0f;

			/*for (int l = 0; l < agentBlue.getHTSL().getLayers().size(); l++) {
				sf::Image sdr;
				sdr.create(agentBlue.getHTSL().getLayerDescs()[l]._width, agentBlue.getHTSL().getLayerDescs()[l]._height);

				for (int x = 0; x < agentBlue.getHTSL().getLayerDescs()[l]._width; x++)
					for (int y = 0; y < agentBlue.getHTSL().getLayerDescs()[l]._height; y++) {
						sf::Color c;
						c.r = c.g = c.b = agentBlue.getHTSL().getLayers()[l]._rsc.getHiddenState(x, y) * 255.0f;

						sdr.setPixel(x, y, c);
					}

				sf::Texture sdrt;
				sdrt.loadFromImage(sdr);

				sf::Sprite sdrs;
				sdrs.setTexture(sdrt);
				sdrs.setPosition(alignment, renderWindow.getSize().y - sdr.getSize().y * scale);
				sdrs.setScale(scale, scale);

				renderWindow.draw(sdrs);

				alignment += scale * sdr.getSize().x;
			}*/

			alignment = 0.0f;

			for (int l = 0; l < agentRed.getHTSL().getLayers().size(); l++) {
				sf::Image sdr;
				sdr.create(agentRed.getHTSL().getLayerDescs()[l]._width, agentRed.getHTSL().getLayerDescs()[l]._height);

				for (int x = 0; x < agentRed.getHTSL().getLayerDescs()[l]._width; x++)
					for (int y = 0; y < agentRed.getHTSL().getLayerDescs()[l]._height; y++) {
						sf::Color c;
						c.r = c.g = c.b = agentRed.getHTSL().getLayers()[l]._rsc.getHiddenState(x, y) * 255.0f;

						sdr.setPixel(x, y, c);
					}

				sf::Texture sdrt;
				sdrt.loadFromImage(sdr);

				alignment += scale * sdr.getSize().x;

				sf::Sprite sdrs;
				sdrs.setTexture(sdrt);
				sdrs.setPosition(renderWindow.getSize().x - alignment, renderWindow.getSize().y - sdr.getSize().y * scale);
				sdrs.setScale(scale, scale);

				renderWindow.draw(sdrs);	
			}
		}

		if (sf::Keyboard::isKeyPressed(sf::Keyboard::T)) {
			sf::Vector2f position;

			const float scalar = 1.0f / 0.001f;

			position.x = red._position.x + scalar * agentRed.getHTSL().getPrediction(0);
			position.y = red._position.y + scalar * agentRed.getHTSL().getPrediction(1);

			sf::Sprite s;
			s.setTexture(ballTexture);
			s.setOrigin(ballTexture.getSize().x * 0.5f, ballTexture.getSize().y * 0.5f);
			s.setPosition(position);

			renderWindow.draw(s);
		}

		if (sf::Keyboard::isKeyPressed(sf::Keyboard::F)) {
			for (int i = 0; i < 16; i++)
				std::cout << agentRed.getHTSL().getPrediction(i) << std::endl;

			std::cout << std::endl;
		}
		
		renderWindow.display();
	} while (!quit);

	return 0;
}