<commit_before>/*
 * Scene.cpp
 *
 *  Created on: 24.01.2015
 *      Author: sartz
 */

#include "Scene.hpp"
#include "Tile.hpp"
#include "globals.hpp"
#include <iostream>
#include "GUI.hpp"
#include <math.h>
#include "globals.hpp"
#include "KeyItem.hpp"

Scene::Scene() {
	// TODO Auto-generated constructor stub
	gameBoard.resize(sizeX * sizeY * largeTileSizeX * largeTileSizeY);

}

Scene::~Scene() {
	// TODO Auto-generated destructor stub
}

GameObject* Scene::getTile(int x, int y)
{
	if (x + y*sizeX < (int)gameBoard.size())
	{
		return gameBoard[x + y * sizeX * largeTileSizeX];
	}
	return 0;
}

void Scene::setTile(GameObject* obj, int x, int y)
{
	gameBoard[x + y * sizeX * largeTileSizeX] = obj;
}

void Scene::setGUI(GUI* obj)
{
	gui = obj;
}

const std::vector<GameObject*> &Scene::getGameBoard() const
{
	return gameBoard;
}

void Scene::switchLargeTile(int x1, int y1, int x2, int y2)
{
	int startX1 = x1*largeTileSizeX;
	int startY1 = y1*largeTileSizeY;
	int startX2 = x2*largeTileSizeX;
	int startY2 = y2*largeTileSizeY;

	for (int x=0;x<largeTileSizeX;x++)
	{
		for (int y=0;y<largeTileSizeY;y++)
		{
			sf::Vector2f tmpPos = getTile(startX1+x, startY1+y)->getPosition();
			sf::Vector2f tmpPos2 = getTile(startX2+x, startY2+y)->getPosition();
			getTile(startX2+x, startY2+y)->setPosition(tmpPos.x, tmpPos.y);
			getTile(startX1+x, startY1+y)->setPosition(tmpPos2.x, tmpPos2.y);
		}
	}
}

void Scene::update(sf::Time deltaT)
{
//	if (sf::Mouse::isButtonPressed(sf::Mouse::Left))
//	{
//		sf::Vector2i globalPosition = sf::Mouse::getPosition(window);
//
//		sf::Vector2f localPosition;
//		localPosition.x = 1.f*globalPosition.x/(Tile::pixelSizeX*Tile::tileScaleFactor);
//		localPosition.y = 1.f*globalPosition.y/(Tile::pixelSizeY*Tile::tileScaleFactor);
//		std::cout<<localPosition.x<<", "<<localPosition.y<<std::endl;
//	}
	/*for (std::vector<GameObject*>::iterator it = gameBoard.begin();it != gameBoard.end(); it++)
	{
		(*it)->update(deltaT);
		std::cout << (*it) << std::endl;
	}*/
	for(auto& obj: gameBoard) {
		obj->update(deltaT);
	}

	for(auto& obj: items) {
		obj->update(deltaT);
	}
	player->update(deltaT);
	if (gui != 0)
	{
		gui->update(deltaT);
	}

	sf::Font font;
	font.loadFromFile(std::string(PATH) + "fonts/LiberationSerif-Regular.ttf");

	sf::Text level;
	level.setFont(font);
	level.setPosition(screenWidth - 30, screenHeight - 70);
	level.setString(std::to_string(sceneManager.getCurrentLevelNumber()));
	window.draw(level);

	for(std::vector<Item*>::iterator itIt = items.begin() ; itIt != items.end() ; itIt++) {
		if (player->intersects(**itIt))
		{
			(*itIt)->applyEffect();
			itIt = items.erase(itIt);
		}
	}

	/*
	// Text TEST
	sf::Vector2f textPos(32.0f, 32.0f);
	* int charSize = 30;

	sf::Text speech;
	speech.setFont(font);

	speech.setColor(sf::Color(210, 210, 255));
	speech.setCharacterSize(charSize);
	speech.setPosition(textPos);

	sf::RectangleShape textRect;
	textRect.setOutlineColor(sf::Color::Blue);
	textRect.setOutlineThickness(5);
	textRect.setPosition(textPos.x - 5, textPos.y - 5);
	textRect.setSize(sf::Vector2f(screenWidth - 2* textPos.x + 10, 2 * charSize + 30));
	textRect.setFillColor(sf::Color(0, 0, 250, 50));
	window.draw(textRect);

	// zu Anfang:
	speech.setStyle(sf::Text::Bold);
	speech.setString("Oh no...");
	speech.setStyle(sf::Text::Regular);
	speech.setString("The time machine is broken, doggie!");
	speech.setString("...");
	speech.setString("What do we do now?");
	speech.setColor(sf::Color(210, 255, 210));
	speech.setString("SQOLRK");
	speech.setColor(sf::Color(210, 210, 255));

	// Zeit wird knapp:
	speech.setColor(sf::Color(210, 255, 210));
	speech.setString("LURMK");
	speech.setColor(sf::Color(210, 210, 255));
	speech.setString("You are right we should hurry. The pizza is going cold.");

	// Key aufgesammelt (erstes Level):
	speech.setColor(sf::Color(210, 210, 210));
	speech.setString("A key to another dimension!");
	speech.setColor(sf::Color(210, 210, 255));

	// Uhr aufgesammelt (erstes Level):
	speech.setColor(sf::Color(210, 210, 210));
	speech.setString("When do we do now?");
	speech.setColor(sf::Color(210, 210, 255));

	// Ziel erreicht, kein Key (erstes Level):
	speech.setString("We need a key for this dimension hole!");

	// Ziel erreicht (erstes Level):
	speech.setString("Do you want to leave, Doggie?");
	speech.setColor(sf::Color(210, 255, 210));
	speech.setString("Frravt");
	speech.setColor(sf::Color(210, 210, 255));

	window.draw(speech);
	*/
}

void Scene::leave()
{
	int size = items.size();
	int keysInLevel = 0;
	for(int i = 0;i < size;i++)
	{
		if (dynamic_cast<KeyItem*>(items[i]))
		{
			keysInLevel++;
		}
	}
	if (keysInLevel > 0)
	{
		return;
	}
	gui->resetCoins();
	gui->resetKeys();
	sceneManager.nextLevel();
}
<commit_msg>spielende idee<commit_after>/*
 * Scene.cpp
 *
 *  Created on: 24.01.2015
 *      Author: sartz
 */

#include "Scene.hpp"
#include "Tile.hpp"
#include "globals.hpp"
#include <iostream>
#include "GUI.hpp"
#include <math.h>
#include "globals.hpp"
#include "KeyItem.hpp"

Scene::Scene() {
	// TODO Auto-generated constructor stub
	gameBoard.resize(sizeX * sizeY * largeTileSizeX * largeTileSizeY);

}

Scene::~Scene() {
	// TODO Auto-generated destructor stub
}

GameObject* Scene::getTile(int x, int y)
{
	if (x + y*sizeX < (int)gameBoard.size())
	{
		return gameBoard[x + y * sizeX * largeTileSizeX];
	}
	return 0;
}

void Scene::setTile(GameObject* obj, int x, int y)
{
	gameBoard[x + y * sizeX * largeTileSizeX] = obj;
}

void Scene::setGUI(GUI* obj)
{
	gui = obj;
}

const std::vector<GameObject*> &Scene::getGameBoard() const
{
	return gameBoard;
}

void Scene::switchLargeTile(int x1, int y1, int x2, int y2)
{
	int startX1 = x1*largeTileSizeX;
	int startY1 = y1*largeTileSizeY;
	int startX2 = x2*largeTileSizeX;
	int startY2 = y2*largeTileSizeY;

	for (int x=0;x<largeTileSizeX;x++)
	{
		for (int y=0;y<largeTileSizeY;y++)
		{
			sf::Vector2f tmpPos = getTile(startX1+x, startY1+y)->getPosition();
			sf::Vector2f tmpPos2 = getTile(startX2+x, startY2+y)->getPosition();
			getTile(startX2+x, startY2+y)->setPosition(tmpPos.x, tmpPos.y);
			getTile(startX1+x, startY1+y)->setPosition(tmpPos2.x, tmpPos2.y);
		}
	}
}

void Scene::update(sf::Time deltaT)
{
//	if (sf::Mouse::isButtonPressed(sf::Mouse::Left))
//	{
//		sf::Vector2i globalPosition = sf::Mouse::getPosition(window);
//
//		sf::Vector2f localPosition;
//		localPosition.x = 1.f*globalPosition.x/(Tile::pixelSizeX*Tile::tileScaleFactor);
//		localPosition.y = 1.f*globalPosition.y/(Tile::pixelSizeY*Tile::tileScaleFactor);
//		std::cout<<localPosition.x<<", "<<localPosition.y<<std::endl;
//	}
	/*for (std::vector<GameObject*>::iterator it = gameBoard.begin();it != gameBoard.end(); it++)
	{
		(*it)->update(deltaT);
		std::cout << (*it) << std::endl;
	}*/
	for(auto& obj: gameBoard) {
		obj->update(deltaT);
	}

	for(auto& obj: items) {
		obj->update(deltaT);
	}
	player->update(deltaT);
	if (gui != 0)
	{
		gui->update(deltaT);
	}

	sf::Font font;
	font.loadFromFile(std::string(PATH) + "fonts/LiberationSerif-Regular.ttf");

	sf::Text level;
	level.setFont(font);
	level.setPosition(screenWidth - 30, screenHeight - 70);
	level.setString(std::to_string(sceneManager.getCurrentLevelNumber()));
	window.draw(level);

	for(std::vector<Item*>::iterator itIt = items.begin() ; itIt != items.end() ; itIt++) {
		if (player->intersects(**itIt))
		{
			(*itIt)->applyEffect();
			itIt = items.erase(itIt);
		}
	}

	/*
	// Text TEST
	sf::Vector2f textPos(32.0f, 32.0f);
	* int charSize = 30;

	sf::Text speech;
	speech.setFont(font);

	speech.setColor(sf::Color(210, 210, 255));
	speech.setCharacterSize(charSize);
	speech.setPosition(textPos);

	sf::RectangleShape textRect;
	textRect.setOutlineColor(sf::Color::Blue);
	textRect.setOutlineThickness(5);
	textRect.setPosition(textPos.x - 5, textPos.y - 5);
	textRect.setSize(sf::Vector2f(screenWidth - 2* textPos.x + 10, 2 * charSize + 30));
	textRect.setFillColor(sf::Color(0, 0, 250, 50));
	window.draw(textRect);

	// zu Anfang:
	speech.setStyle(sf::Text::Bold);
	speech.setString("Oh no...");
	speech.setStyle(sf::Text::Regular);
	speech.setString("The time machine is broken, doggie!");
	speech.setString("...");
	speech.setString("What do we do now?");
	speech.setColor(sf::Color(210, 255, 210));
	speech.setString("SQOLRK");
	speech.setColor(sf::Color(210, 210, 255));

	// Zeit wird knapp:
	speech.setColor(sf::Color(210, 255, 210));
	speech.setString("LURMK");
	speech.setColor(sf::Color(210, 210, 255));
	speech.setString("You are right we should hurry. The pizza is going cold.");

	// Key aufgesammelt (erstes Level):
	speech.setColor(sf::Color(210, 210, 210));
	speech.setString("A key to another dimension!");
	speech.setColor(sf::Color(210, 210, 255));

	// Uhr aufgesammelt (erstes Level):
	speech.setColor(sf::Color(210, 210, 210));
	speech.setString("When do we do now?");
	speech.setColor(sf::Color(210, 210, 255));

	// Ziel erreicht, kein Key (erstes Level):
	speech.setString("We need a key for this dimension hole!");

	// Ziel erreicht (erstes Level):
	speech.setString("Do you want to leave, Doggie?");
	speech.setColor(sf::Color(210, 255, 210));
	speech.setString("Frravt");
	speech.setColor(sf::Color(210, 210, 255));

	// Spielende:
	schwarzer Bildschirm
	speech.setColor(sf::Color(210, 255, 210));
	speech.setString("SQOLRK");
	speech.setColor(sf::Color(210, 210, 255));
	schwarzer Bildschirm

	window.draw(speech);
	*/
}

void Scene::leave()
{
	int size = items.size();
	int keysInLevel = 0;
	for(int i = 0;i < size;i++)
	{
		if (dynamic_cast<KeyItem*>(items[i]))
		{
			keysInLevel++;
		}
	}
	if (keysInLevel > 0)
	{
		return;
	}
	gui->resetCoins();
	gui->resetKeys();
	sceneManager.nextLevel();
}
<|endoftext|>


<commit_before>#include <RayTracer\Scene.h>

#include <RayTracer\SceneParser.h>
#include <RayTracer\RayTraceImage.h>
#include <RayTracer\Camera.h>

#include <RayTracer\Helper.h>

#include <iostream>

Scene::Scene() {
    // default values
    _maxdepth = 5;
    _outputFilename = "SceneRender.png";

    _image = NULL;
    _camera = NULL;

    _size.width  = 200;
    _size.height = 200;
}
Scene::~Scene() {
    if (_camera)
        delete _camera;
}

void Scene::loadScene(std::string sceneFile) {
    SceneParser parser(sceneFile);
    *this = *parser.load();

    if (_image)
        delete _image;
    _image = new RayTraceImage(_size.width, _size.height);
}

void Scene::render() {
    _camera->initFov((float)_size.width, (float)_size.height);
    Sample sample;
    Ray ray;
    vec3 hitPoint;

    while(_image->getSample(sample)) {
        _camera->generateRay(sample, ray);

        Intersection Hit = trace(ray, 0);

        _image->commit(sample, Hit.color);
    }

    _image->save(_outputFilename);
}

Intersection Scene::inShadow(Ray &ray, float t_hit = FLT_MAX) {
    Intersection ret;
    ret.obj = nullptr;

    float t;
    for (std::vector<Primitive*>::iterator it = _primitives.begin(); it < _primitives.end(); ++it) {
        Intersection hit;
        t = (*it)->Intersect(ray, hit);
        if (t > 0 && t < t_hit) {
            t_hit = t;
            ret = hit;
        }
    }

    return ret;
}

Intersection Scene::trace(Ray &ray, int depth) {
    float t_hit = FLT_MAX;
    Intersection ret;
    ret.obj = nullptr;

    if (depth <= this->_maxdepth) {
        float t;
        Intersection hit;
        for (std::vector<Primitive*>::iterator it = _primitives.begin(); it < _primitives.end(); ++it) {
            t = (*it)->Intersect(ray, hit);
            if (t > 0 && t < t_hit) {
                t_hit = t;
                ret = hit;
            }
        }
    }

    // got a hit point -> get color!
    if (ret.obj) {
        ret.color = shade(ret, ray, depth);
    }

    return ret;
}

vec3 Scene::shade(Intersection &Hit, Ray &ray, int depth) {
    vec3 color(0.0);
    color += Hit.obj->ambient;
    color += Hit.obj->emission;

    for (std::vector<Light>::iterator it = _lights.begin(); it != _lights.end(); ++it) {
        vec3 dir_to_light = it->LightVectorFrom(Hit.hitPoint);

        // light in front of object?
        if (dot(Hit.normal, dir_to_light) > 0) {
            Ray r(Hit.hitPoint +0.001f*dir_to_light, dir_to_light);

            Intersection ShadowHit = inShadow(r);
            if (ShadowHit.obj) {
                // only consider position lights for shadow testing
                if (it->pos_or_dir[3] == 1) {
                    float len_to_light        = glm::distance(vec3(it->pos_or_dir), r.pos);
                    float len_to_intersection = glm::distance(ShadowHit.hitPoint, r.pos);

                    if (len_to_intersection <= len_to_light)
                        // Hit.hitPoint in shadow, next light
                        continue;
                }
            }

            vec3 L = it->color;

            // only consider point light for attenuation
            if (it->pos_or_dir[3] == 1) {
                float d = glm::distance(Hit.hitPoint, vec3(it->pos_or_dir));
                L = it->color / (it->attenuation[0] + it->attenuation[1] * d + it->attenuation[2] * d * d);
            }

            // diffuse term
            float dotP = dot(Hit.normal, dir_to_light);
            color += L * (Hit.obj->diffuse * common::max(dotP, 0.0f));

            // specular term
            vec3 halfVec = normalize(dir_to_light + -ray.dir);
            float halfAngle = dot(Hit.normal, halfVec);
            color += L * (Hit.obj->specular * pow(common::max(halfAngle, 0.0f), Hit.obj->shininess));
        }
    }

    // reflection
    // R = V  2 * (VN) * N

    Ray reflectionRay;
    reflectionRay.dir = ray.dir - 2 * dot(ray.dir, Hit.normal) * Hit.normal;
    reflectionRay.pos = Hit.hitPoint + 0.01f*reflectionRay.dir;

    Intersection t = this->trace(reflectionRay, depth+1);
    if (t.obj)
        color += Hit.obj->specular * t.color;

    return color;
}
<commit_msg>scene6 done! fixed shadow testing for directional light<commit_after>#include <RayTracer\Scene.h>

#include <RayTracer\SceneParser.h>
#include <RayTracer\RayTraceImage.h>
#include <RayTracer\Camera.h>

#include <RayTracer\Helper.h>

#include <iostream>

Scene::Scene() {
    // default values
    _maxdepth = 5;
    _outputFilename = "SceneRender.png";

    _image = NULL;
    _camera = NULL;

    _size.width  = 200;
    _size.height = 200;
}
Scene::~Scene() {
    if (_camera)
        delete _camera;
}

void Scene::loadScene(std::string sceneFile) {
    SceneParser parser(sceneFile);
    *this = *parser.load();

    if (_image)
        delete _image;
    _image = new RayTraceImage(_size.width, _size.height);
}

void Scene::render() {
    _camera->initFov((float)_size.width, (float)_size.height);
    Sample sample;
    Ray ray;
    vec3 hitPoint;

    while(_image->getSample(sample)) {
        _camera->generateRay(sample, ray);

        Intersection Hit = trace(ray, 0);

        _image->commit(sample, Hit.color);
    }

    _image->save(_outputFilename);
}

Intersection Scene::inShadow(Ray &ray, float t_hit = FLT_MAX) {
    Intersection ret;
    ret.obj = nullptr;

    float t;
    for (std::vector<Primitive*>::iterator it = _primitives.begin(); it < _primitives.end(); ++it) {
        Intersection hit;
        t = (*it)->Intersect(ray, hit);
        if (t > 0 && t < t_hit) {
            t_hit = t;
            ret = hit;
        }
    }

    return ret;
}

Intersection Scene::trace(Ray &ray, int depth) {
    float t_hit = FLT_MAX;
    Intersection ret;
    ret.obj = nullptr;

    if (depth <= this->_maxdepth) {
        float t;
        Intersection hit;
        for (std::vector<Primitive*>::iterator it = _primitives.begin(); it < _primitives.end(); ++it) {
            t = (*it)->Intersect(ray, hit);
            if (t > 0 && t < t_hit) {
                t_hit = t;
                ret = hit;
            }
        }
    }

    // got a hit point -> get color!
    if (ret.obj) {
        ret.color = shade(ret, ray, depth);
    }

    return ret;
}

vec3 Scene::shade(Intersection &Hit, Ray &ray, int depth) {
    vec3 color(0.0);
    color += Hit.obj->ambient;
    color += Hit.obj->emission;

    for (std::vector<Light>::iterator it = _lights.begin(); it != _lights.end(); ++it) {
        vec3 dir_to_light = it->LightVectorFrom(Hit.hitPoint);

        // light in front of object?
        if (dot(Hit.normal, dir_to_light) > 0) {
            Ray r(Hit.hitPoint +0.001f*dir_to_light, dir_to_light);

            Intersection ShadowHit = inShadow(r);
            if (ShadowHit.obj) {
                // if i'm testing against point light: check if intersection is between startpoint and light!
                // the startpoint is in shadow only then!
                if (it->pos_or_dir[3] == 1) {
                    float len_to_light        = glm::distance(vec3(it->pos_or_dir), Hit.hitPoint);
                    float len_to_intersection = glm::distance(ShadowHit.hitPoint, Hit.hitPoint);

                    if (len_to_intersection <= len_to_light)
                        // Hit.hitPoint in shadow, next light
                        continue;
                } else {
                    // intersection with directional light
                    continue;
                }
            }

            vec3 L = it->color;

            // only consider point light for attenuation (directional light would be 1 0 0 -> no change)
            if (it->pos_or_dir[3] == 1) {
                float d = glm::distance(Hit.hitPoint, vec3(it->pos_or_dir));
                L = it->color / (it->attenuation[0] + it->attenuation[1] * d + it->attenuation[2] * d * d);
            }

            // diffuse term
            float dotP = dot(Hit.normal, dir_to_light);
            color += L * (Hit.obj->diffuse * common::max(dotP, 0.0f));

            // specular term
            vec3 halfVec = normalize(dir_to_light + -ray.dir);
            float halfAngle = dot(Hit.normal, halfVec);
            color += L * (Hit.obj->specular * pow(common::max(halfAngle, 0.0f), Hit.obj->shininess));
        }
    }

    // reflection
    // R = V  2 * (VN) * N

    Ray reflectionRay;
    reflectionRay.dir = ray.dir - 2 * dot(ray.dir, Hit.normal) * Hit.normal;
    reflectionRay.pos = Hit.hitPoint + 0.01f*reflectionRay.dir;

    Intersection t = this->trace(reflectionRay, depth+1);
    if (t.obj)
        color += Hit.obj->specular * t.color;

    return color;
}
<|endoftext|>


<commit_before>/*
 * Scene.cpp
 *
 *  Created on: 24.01.2015
 *      Author: sartz
 */

#include "Scene.hpp"
#include "Tile.hpp"
#include "globals.hpp"
#include <iostream>
#include "GUI.hpp"
#include <math.h>
#include "globals.hpp"
#include "KeyItem.hpp"

Scene::Scene() {
	// TODO Auto-generated constructor stub
	gameBoard.resize(sizeX * sizeY * largeTileSizeX * largeTileSizeY);

}

Scene::~Scene() {
	// TODO Auto-generated destructor stub
}

GameObject* Scene::getTile(int x, int y)
{
	if (x + y*sizeX < (int)gameBoard.size())
	{
		return gameBoard[x + y * sizeX * largeTileSizeX];
	}
	return 0;
}

void Scene::setTile(GameObject* obj, int x, int y)
{
	gameBoard[x + y * sizeX * largeTileSizeX] = obj;
}

void Scene::setGUI(GUI* obj)
{
	gui = obj;
}

const std::vector<GameObject*> &Scene::getGameBoard() const
{
	return gameBoard;
}

void Scene::switchLargeTile(int x1, int y1, int x2, int y2)
{
	int startX1 = x1*largeTileSizeX;
	int startY1 = y1*largeTileSizeY;
	int startX2 = x2*largeTileSizeX;
	int startY2 = y2*largeTileSizeY;

	for (int x=0;x<largeTileSizeX;x++)
	{
		for (int y=0;y<largeTileSizeY;y++)
		{
			sf::Vector2f tmpPos = getTile(startX1+x, startY1+y)->getPosition();
			sf::Vector2f tmpPos2 = getTile(startX2+x, startY2+y)->getPosition();
			getTile(startX2+x, startY2+y)->setPosition(tmpPos.x, tmpPos.y);
			getTile(startX1+x, startY1+y)->setPosition(tmpPos2.x, tmpPos2.y);
		}
	}
}

void Scene::update(sf::Time deltaT)
{
//	if (sf::Mouse::isButtonPressed(sf::Mouse::Left))
//	{
//		sf::Vector2i globalPosition = sf::Mouse::getPosition(window);
//
//		sf::Vector2f localPosition;
//		localPosition.x = 1.f*globalPosition.x/(Tile::pixelSizeX*Tile::tileScaleFactor);
//		localPosition.y = 1.f*globalPosition.y/(Tile::pixelSizeY*Tile::tileScaleFactor);
//		std::cout<<localPosition.x<<", "<<localPosition.y<<std::endl;
//	}
	/*for (std::vector<GameObject*>::iterator it = gameBoard.begin();it != gameBoard.end(); it++)
	{
		(*it)->update(deltaT);
		std::cout << (*it) << std::endl;
	}*/
	for(auto& obj: gameBoard) {
		obj->update(deltaT);
	}

	for(auto& obj: items) {
		obj->update(deltaT);
	}
	player->update(deltaT);
	if (gui != 0)
	{
		gui->update(deltaT);
	}

	sf::Font font;
	font.loadFromFile(std::string(PATH) + "fonts/LiberationSerif-Regular.ttf");

	sf::Text level;
	level.setFont(font);
	level.setPosition(screenWidth - 30, screenHeight - 70);
	level.setString(std::to_string(sceneManager.getCurrentLevelNumber()));
	window.draw(level);

	for(std::vector<Item*>::iterator itIt = items.begin() ; itIt != items.end() ; itIt++) {
		if (player->intersects(**itIt))
		{
			(*itIt)->applyEffect();
			itIt = items.erase(itIt);
		}
	}

	/*
	// Text TEST
	sf::Vector2f textPos(32.0f, 32.0f);
	* int charSize = 30;

	sf::Text speech;
	speech.setFont(font);

	speech.setColor(sf::Color(210, 210, 255));
	speech.setCharacterSize(charSize);
	speech.setPosition(textPos);

	sf::RectangleShape textRect;
	textRect.setOutlineColor(sf::Color::Blue);
	textRect.setOutlineThickness(5);
	textRect.setPosition(textPos.x - 5, textPos.y - 5);
	textRect.setSize(sf::Vector2f(screenWidth - 2* textPos.x + 10, 2 * charSize + 30));
	textRect.setFillColor(sf::Color(0, 0, 250, 50));
	window.draw(textRect);

	// zu Anfang:
	speech.setStyle(sf::Text::Bold);
	speech.setString("Oh no...");
	speech.setStyle(sf::Text::Regular);
	speech.setString("The time machine is broken, doggie!");
	speech.setString("...");
	speech.setString("What do we do now?");
	speech.setColor(sf::Color(210, 255, 210));
	speech.setString("SQOLRK");
	speech.setColor(sf::Color(210, 210, 255));

	// Zeit wird knapp:
	speech.setColor(sf::Color(210, 255, 210));
	speech.setString("LURMK");
	speech.setColor(sf::Color(210, 210, 255));
	speech.setString("You are right we should hurry. The pizza is going cold.");

	// Key aufgesammelt (erstes Level):
	speech.setColor(sf::Color(210, 210, 210));
	speech.setString("A key to another dimension!");
	speech.setColor(sf::Color(210, 210, 255));

	// Uhr aufgesammelt (erstes Level):
	speech.setColor(sf::Color(210, 210, 210));
	speech.setString("When do we do now?");
	speech.setColor(sf::Color(210, 210, 255));

	// Ziel erreicht, kein Key (erstes Level):
	speech.setString("We need a key for this dimension hole!");

	// Ziel erreicht (erstes Level):
	speech.setString("Do you want to leave, Doggie?");
	speech.setColor(sf::Color(210, 255, 210));
	speech.setString("Frravt");
	speech.setColor(sf::Color(210, 210, 255));

	window.draw(speech);
	*/
}

void Scene::leave()
{
	int size = items.size();
	int keysInLevel = 0;
	for(int i = 0;i < size;i++)
	{
		if (dynamic_cast<KeyItem*>(items[i]))
		{
			keysInLevel++;
		}
	}
	if (keysInLevel > 0)
	{
		return;
	}
	gui->resetCoins();
	gui->resetKeys();
	sceneManager.nextLevel();
}
<commit_msg>kleiner Bugfix beim Item-AUfsammeln<commit_after>/*
 * Scene.cpp
 *
 *  Created on: 24.01.2015
 *      Author: sartz
 */

#include "Scene.hpp"
#include "Tile.hpp"
#include "globals.hpp"
#include <iostream>
#include "GUI.hpp"
#include <math.h>
#include "globals.hpp"
#include "KeyItem.hpp"

Scene::Scene() {
	// TODO Auto-generated constructor stub
	gameBoard.resize(sizeX * sizeY * largeTileSizeX * largeTileSizeY);

}

Scene::~Scene() {
	// TODO Auto-generated destructor stub
}

GameObject* Scene::getTile(int x, int y)
{
	if (x + y*sizeX < (int)gameBoard.size())
	{
		return gameBoard[x + y * sizeX * largeTileSizeX];
	}
	return 0;
}

void Scene::setTile(GameObject* obj, int x, int y)
{
	gameBoard[x + y * sizeX * largeTileSizeX] = obj;
}

void Scene::setGUI(GUI* obj)
{
	gui = obj;
}

const std::vector<GameObject*> &Scene::getGameBoard() const
{
	return gameBoard;
}

void Scene::switchLargeTile(int x1, int y1, int x2, int y2)
{
	int startX1 = x1*largeTileSizeX;
	int startY1 = y1*largeTileSizeY;
	int startX2 = x2*largeTileSizeX;
	int startY2 = y2*largeTileSizeY;

	for (int x=0;x<largeTileSizeX;x++)
	{
		for (int y=0;y<largeTileSizeY;y++)
		{
			sf::Vector2f tmpPos = getTile(startX1+x, startY1+y)->getPosition();
			sf::Vector2f tmpPos2 = getTile(startX2+x, startY2+y)->getPosition();
			getTile(startX2+x, startY2+y)->setPosition(tmpPos.x, tmpPos.y);
			getTile(startX1+x, startY1+y)->setPosition(tmpPos2.x, tmpPos2.y);
		}
	}
}

void Scene::update(sf::Time deltaT)
{
//	if (sf::Mouse::isButtonPressed(sf::Mouse::Left))
//	{
//		sf::Vector2i globalPosition = sf::Mouse::getPosition(window);
//
//		sf::Vector2f localPosition;
//		localPosition.x = 1.f*globalPosition.x/(Tile::pixelSizeX*Tile::tileScaleFactor);
//		localPosition.y = 1.f*globalPosition.y/(Tile::pixelSizeY*Tile::tileScaleFactor);
//		std::cout<<localPosition.x<<", "<<localPosition.y<<std::endl;
//	}
	/*for (std::vector<GameObject*>::iterator it = gameBoard.begin();it != gameBoard.end(); it++)
	{
		(*it)->update(deltaT);
		std::cout << (*it) << std::endl;
	}*/
	for(auto& obj: gameBoard) {
		obj->update(deltaT);
	}

	for(auto& obj: items) {
		obj->update(deltaT);
	}
	player->update(deltaT);
	if (gui != 0)
	{
		gui->update(deltaT);
	}

	sf::Font font;
	font.loadFromFile(std::string(PATH) + "fonts/LiberationSerif-Regular.ttf");

	sf::Text level;
	level.setFont(font);
	level.setPosition(screenWidth - 30, screenHeight - 70);
	level.setString(std::to_string(sceneManager.getCurrentLevelNumber()));
	window.draw(level);

	for(std::vector<Item*>::iterator itIt = items.begin() ; itIt != items.end() ; ) {
		if (player->intersects(**itIt))
		{
			(*itIt)->applyEffect();
			itIt = items.erase(itIt);
		}
		else
		{
			itIt ++;
		}
	}

	/*
	// Text TEST
	sf::Vector2f textPos(32.0f, 32.0f);
	* int charSize = 30;

	sf::Text speech;
	speech.setFont(font);

	speech.setColor(sf::Color(210, 210, 255));
	speech.setCharacterSize(charSize);
	speech.setPosition(textPos);

	sf::RectangleShape textRect;
	textRect.setOutlineColor(sf::Color::Blue);
	textRect.setOutlineThickness(5);
	textRect.setPosition(textPos.x - 5, textPos.y - 5);
	textRect.setSize(sf::Vector2f(screenWidth - 2* textPos.x + 10, 2 * charSize + 30));
	textRect.setFillColor(sf::Color(0, 0, 250, 50));
	window.draw(textRect);

	// zu Anfang:
	speech.setStyle(sf::Text::Bold);
	speech.setString("Oh no...");
	speech.setStyle(sf::Text::Regular);
	speech.setString("The time machine is broken, doggie!");
	speech.setString("...");
	speech.setString("What do we do now?");
	speech.setColor(sf::Color(210, 255, 210));
	speech.setString("SQOLRK");
	speech.setColor(sf::Color(210, 210, 255));

	// Zeit wird knapp:
	speech.setColor(sf::Color(210, 255, 210));
	speech.setString("LURMK");
	speech.setColor(sf::Color(210, 210, 255));
	speech.setString("You are right we should hurry. The pizza is going cold.");

	// Key aufgesammelt (erstes Level):
	speech.setColor(sf::Color(210, 210, 210));
	speech.setString("A key to another dimension!");
	speech.setColor(sf::Color(210, 210, 255));

	// Uhr aufgesammelt (erstes Level):
	speech.setColor(sf::Color(210, 210, 210));
	speech.setString("When do we do now?");
	speech.setColor(sf::Color(210, 210, 255));

	// Ziel erreicht, kein Key (erstes Level):
	speech.setString("We need a key for this dimension hole!");

	// Ziel erreicht (erstes Level):
	speech.setString("Do you want to leave, Doggie?");
	speech.setColor(sf::Color(210, 255, 210));
	speech.setString("Frravt");
	speech.setColor(sf::Color(210, 210, 255));

	window.draw(speech);
	*/
}

void Scene::leave()
{
	int size = items.size();
	int keysInLevel = 0;
	for(int i = 0;i < size;i++)
	{
		if (dynamic_cast<KeyItem*>(items[i]))
		{
			keysInLevel++;
		}
	}
	if (keysInLevel > 0)
	{
		return;
	}
	gui->resetCoins();
	gui->resetKeys();
	sceneManager.nextLevel();
}
<|endoftext|>


<commit_before>#include <cstdio>
#include <cstdlib>
#include <set>
#include <cstring>
#include <ctime>

#include "Search.h"
#include "Utils.h"

using namespace std;

//
// Static Variables
//
uint64_t nextId = 1;

// TODO(gabor) this is not threadsafe
inline uint64_t generateUniqueId() {
  nextId++;
}

//
// Class Path
//
Path::Path(const Path* parentOrNull, const word* fact, uint8_t factLength, edge_type edgeType)
    : parent(parentOrNull),
      fact(fact),
      factLength(factLength),
      edgeType(edgeType) { }

Path::Path(const word* fact, uint8_t factLength)
    : parent(NULL),
      fact(fact),
      factLength(factLength),
      edgeType(255) { }

Path::~Path() {
};

bool Path::operator==(const Path& other) const {
  // Check metadata
  if ( !( edgeType == other.edgeType && factLength == other.factLength ) ) {
    return false;
  }
  // Check fact content
  for (int i = 0; i < factLength; ++i) {
    if (other.fact[i] != fact[i]) {
      return false;
    }
  }
  // Return true
  return true;
}

//
// Class SearchType
//

//
// Class BreadthFirstSearch
//
BreadthFirstSearch::BreadthFirstSearch()
    : fringeLength(0), fringeCapacity(1), fringeI(0),
      poolCapacity(1), poolLength(0), poppedRoot(false),
      sumOffset(0){
  this->fringe = (Path*) malloc(fringeCapacity * sizeof(Path));
  this->memoryPool = (word*) malloc(poolCapacity * sizeof(word*));
}

BreadthFirstSearch::~BreadthFirstSearch() {
  free(this->fringe);
  free(this->memoryPool);
  delete this->root;
}

void BreadthFirstSearch::push(
    const Path* parent, uint8_t mutationIndex,
    uint8_t replaceLength, word replace1, word replace2, edge_type edge) {

  // Allocate new fact
  // (ensure space)
  while (poolLength + parent->factLength >= poolCapacity) {
    // (re-allocate array)
    word* newPool = (word*) malloc(2 * poolCapacity * sizeof(word*));
    uint64_t startOffset = ((uint64_t) newPool) - ((uint64_t) memoryPool);
    memcpy(newPool, memoryPool, poolCapacity * sizeof(word*));
    free(memoryPool);
    memoryPool = newPool;
    poolCapacity = 2 * poolCapacity;
    // (fix pointers -- and God help me for pointer arithmetic)
    for (int i = 0; i < fringeLength; ++i) {
      fringe[i].fact = (word*) (startOffset + ((uint64_t) fringe[i].fact));
    }
  }
  // (allocate fact)
  uint8_t mutatedLength = parent->factLength - 1 + replaceLength;
  word* mutated = &memoryPool[poolLength];
  poolLength += mutatedLength;
  // (mutate fact)
  memcpy(mutated, parent->fact, mutationIndex * sizeof(word));
  if (replaceLength > 0) { mutated[mutationIndex] = replace1; }
  if (replaceLength > 1) { mutated[mutationIndex + 1] = replace2; }
  memcpy(&(mutated[mutationIndex + replaceLength]),
         &(parent->fact[mutationIndex + 1]),
         (parent->factLength - mutationIndex - 1) * sizeof(word));

  // Allocate new path
  // (ensure space)
  while (fringeLength >= fringeCapacity) {
    // (re-allocate array)
    Path* newFringe = (Path*) malloc(2 * fringeCapacity * sizeof(Path));
    uint64_t startOffset = ((uint64_t) newFringe) - ((uint64_t) fringe);
    memcpy(newFringe, fringe, fringeCapacity * sizeof(Path));
    free(fringe);
    fringe = newFringe;
    fringeCapacity = 2 * fringeCapacity;
    // (fix pointers -- and God help me for pointer arithmetic)
    for (int i = 0; i < fringeLength; ++i) {
      if (fringe[i].parent != root) {
        fringe[i].parent = (Path*) (startOffset + ((uint64_t) fringe[i].parent));
      }
    }
    if (parent != root) {
      parent = (Path*) (startOffset + ((uint64_t) parent));
    }
  }
  // (allocate path)
  fringeLength += 1;
  new(&fringe[fringeLength-1]) Path(parent, mutated, mutatedLength, edge);
}

const Path* BreadthFirstSearch::peek() {
  if (!poppedRoot && this->fringeI == 0) {
    poppedRoot = true;
    return root;
  }
  return &this->fringe[this->fringeI];
}

const Path* BreadthFirstSearch::pop() {
  if (!poppedRoot && this->fringeI == 0) {
    poppedRoot = true;
    return root;
  }
  this->fringeI += 1;
  return &this->fringe[this->fringeI - 1];
}

bool BreadthFirstSearch::isEmpty() {
  return root == NULL || (poppedRoot && fringeI >= fringeLength);
}

//
// Class CacheStrategy
//

//
// Class CacheStrategyNone
//
bool CacheStrategyNone::isSeen(const Path&) {
  return false;
}

void CacheStrategyNone::add(const Path&) { }

//
// Function search()
//
vector<const Path*> Search(Graph* graph, FactDB* knownFacts,
                     const word* queryFact, const uint8_t queryFactLength,
                     SearchType* fringe, CacheStrategy* cache,
                     const uint64_t timeout) {
  //
  // Setup
  //
  // Create a vector for the return value to occupy
  vector<const Path*> responses;
  // Create the start state
  fringe->root = new Path(queryFact, queryFactLength);  // I need the memory to not go away
  // Initialize timer (number of elements popped from the fringe)
  uint64_t time = 0;
  const uint32_t tickTime = 10000;
  std::clock_t startTime = std::clock();

  //
  // Search
  //
  while (!fringe->isEmpty() && time < timeout) {
    // Get the next element from the fringe
    if (fringe->isEmpty()) {
      printf("IMPOSSIBLE: the search fringe is empty. This means (a) there are leaf nodes in the graph, and (b) this would have caused a memory leak.\n");
      std::exit(1);
    }
    const Path* parent = fringe->pop();
    // Update time
    time += 1;
//    printf("search tick %lu; popped %s\n", time, toString(*graph, *fringe, parent).c_str());
    if (time % tickTime == 0) {
      const uint32_t tickOOM
        = tickTime < 1000 ? 1 : (tickTime < 1000000 ? 1000 : (tickTime  < 1000000000 ? 1000000 : 1) );
      printf("[%lu%s / %lu%s search tick]; %lu paths found (%f ms elapsed)\n",
             time / tickOOM,
             tickTime < 1000 ? "" : (tickTime < 999999 ? "k" : (tickTime  < 999999999 ? "m" : "") ),
             timeout / tickOOM,
             tickTime < 1000 ? "" : (tickTime < 999999 ? "k" : (tickTime  < 999999999 ? "m" : "") ),
             responses.size(),
             1000.0 * ( std::clock() - startTime ) / ((double) CLOCKS_PER_SEC));
    }

    // -- Check If Valid --
    if (knownFacts->contains(parent->fact, parent->factLength)) {
      printf("> %s\n", toString(*graph, *fringe, parent).c_str());
      responses.push_back(parent);
    }

    // -- Mutations --
    for (int indexToMutate = 0;
         indexToMutate < parent->factLength;
         ++indexToMutate) {  // for each index to mutate...
      const vector<edge>& mutations
        = graph->outgoingEdges(parent->fact[indexToMutate]);
//      printf("  mutating index %d; %lu children\n", indexToMutate, mutations.size());
      for(vector<edge>::const_iterator it = mutations.begin();
          it != mutations.end();
          ++it) {  // for each possible mutation on that index...
        if (it->type > 1) { continue; } // TODO(gabor) don't only do WordNet jumps
        // Add the state to the fringe
        fringe->push(parent, indexToMutate, 1, it->sink, 0, it->type);
      }
    }
  }

  printf("Search complete; %lu paths found\n", responses.size());
  return responses;
}

<commit_msg>Add some debug output<commit_after>#include <cstdio>
#include <cstdlib>
#include <set>
#include <cstring>
#include <ctime>

#include "Search.h"
#include "Utils.h"

using namespace std;

//
// Static Variables
//
uint64_t nextId = 1;

// TODO(gabor) this is not threadsafe
inline uint64_t generateUniqueId() {
  nextId++;
}

//
// Class Path
//
Path::Path(const Path* parentOrNull, const word* fact, uint8_t factLength, edge_type edgeType)
    : parent(parentOrNull),
      fact(fact),
      factLength(factLength),
      edgeType(edgeType) { }

Path::Path(const word* fact, uint8_t factLength)
    : parent(NULL),
      fact(fact),
      factLength(factLength),
      edgeType(255) { }

Path::~Path() {
};

bool Path::operator==(const Path& other) const {
  // Check metadata
  if ( !( edgeType == other.edgeType && factLength == other.factLength ) ) {
    return false;
  }
  // Check fact content
  for (int i = 0; i < factLength; ++i) {
    if (other.fact[i] != fact[i]) {
      return false;
    }
  }
  // Return true
  return true;
}

//
// Class SearchType
//

//
// Class BreadthFirstSearch
//
BreadthFirstSearch::BreadthFirstSearch()
    : fringeLength(0), fringeCapacity(1), fringeI(0),
      poolCapacity(1), poolLength(0), poppedRoot(false),
      sumOffset(0){
  this->fringe = (Path*) malloc(fringeCapacity * sizeof(Path));
  this->memoryPool = (word*) malloc(poolCapacity * sizeof(word*));
}

BreadthFirstSearch::~BreadthFirstSearch() {
  free(this->fringe);
  free(this->memoryPool);
  delete this->root;
}

void BreadthFirstSearch::push(
    const Path* parent, uint8_t mutationIndex,
    uint8_t replaceLength, word replace1, word replace2, edge_type edge) {

  // Allocate new fact
  // (ensure space)
  while (poolLength + parent->factLength >= poolCapacity) {
    // (re-allocate array)
    word* newPool = (word*) malloc(2 * poolCapacity * sizeof(word*));
    uint64_t startOffset = ((uint64_t) newPool) - ((uint64_t) memoryPool);
    memcpy(newPool, memoryPool, poolCapacity * sizeof(word*));
    free(memoryPool);
    memoryPool = newPool;
    poolCapacity = 2 * poolCapacity;
    // (fix pointers -- and God help me for pointer arithmetic)
    for (int i = 0; i <fringeLength; ++i) {
      fringe[i].fact = (word*) (startOffset + ((uint64_t) fringe[i].fact));
    }
    printf("Pool capacity is now %lu\n", poolCapacity);
  }
  // (allocate fact)
  uint8_t mutatedLength = parent->factLength - 1 + replaceLength;
  word* mutated = &memoryPool[poolLength];
  poolLength += mutatedLength;
  // (mutate fact)
  memcpy(mutated, parent->fact, mutationIndex * sizeof(word));
  if (replaceLength > 0) { mutated[mutationIndex] = replace1; }
  if (replaceLength > 1) { mutated[mutationIndex + 1] = replace2; }
  memcpy(&(mutated[mutationIndex + replaceLength]),
         &(parent->fact[mutationIndex + 1]),
         (parent->factLength - mutationIndex - 1) * sizeof(word));

  // Allocate new path
  // (ensure space)
  while (fringeLength >= fringeCapacity) {
    // (re-allocate array)
    Path* newFringe = (Path*) malloc(2 * fringeCapacity * sizeof(Path));
    uint64_t startOffset = ((uint64_t) newFringe) - ((uint64_t) fringe);
    memcpy(newFringe, fringe, fringeCapacity * sizeof(Path));
    free(fringe);
    fringe = newFringe;
    fringeCapacity = 2 * fringeCapacity;
    // (fix pointers -- and God help me for pointer arithmetic)
    for (int i = 0; i < fringeLength; ++i) {
      if (fringe[i].parent != root) {
        fringe[i].parent = (Path*) (startOffset + ((uint64_t) fringe[i].parent));
      }
    }
    if (parent != root) {
      parent = (Path*) (startOffset + ((uint64_t) parent));
    }
    printf("Fringe capacity is now %lu\n", fringeCapacity);
  }
  // (allocate path)
  fringeLength += 1;
  new(&fringe[fringeLength-1]) Path(parent, mutated, mutatedLength, edge);
}

const Path* BreadthFirstSearch::peek() {
  if (!poppedRoot && this->fringeI == 0) {
    poppedRoot = true;
    return root;
  }
  return &this->fringe[this->fringeI];
}

const Path* BreadthFirstSearch::pop() {
  if (!poppedRoot && this->fringeI == 0) {
    poppedRoot = true;
    return root;
  }
  this->fringeI += 1;
  return &this->fringe[this->fringeI - 1];
}

bool BreadthFirstSearch::isEmpty() {
  return root == NULL || (poppedRoot && fringeI >= fringeLength);
}

//
// Class CacheStrategy
//

//
// Class CacheStrategyNone
//
bool CacheStrategyNone::isSeen(const Path&) {
  return false;
}

void CacheStrategyNone::add(const Path&) { }

//
// Function search()
//
vector<const Path*> Search(Graph* graph, FactDB* knownFacts,
                     const word* queryFact, const uint8_t queryFactLength,
                     SearchType* fringe, CacheStrategy* cache,
                     const uint64_t timeout) {
  //
  // Setup
  //
  // Create a vector for the return value to occupy
  vector<const Path*> responses;
  // Create the start state
  fringe->root = new Path(queryFact, queryFactLength);  // I need the memory to not go away
  // Initialize timer (number of elements popped from the fringe)
  uint64_t time = 0;
  const uint32_t tickTime = 10000;
  std::clock_t startTime = std::clock();

  //
  // Search
  //
  while (!fringe->isEmpty() && time < timeout) {
    // Get the next element from the fringe
    if (fringe->isEmpty()) {
      printf("IMPOSSIBLE: the search fringe is empty. This means (a) there are leaf nodes in the graph, and (b) this would have caused a memory leak.\n");
      std::exit(1);
    }
    const Path* parent = fringe->pop();
    // Update time
    time += 1;
//    printf("search tick %lu; popped %s\n", time, toString(*graph, *fringe, parent).c_str());
    if (time % tickTime == 0) {
      const uint32_t tickOOM
        = tickTime < 1000 ? 1 : (tickTime < 1000000 ? 1000 : (tickTime  < 1000000000 ? 1000000 : 1) );
      printf("[%lu%s / %lu%s search tick]; %lu paths found (%f ms elapsed)\n",
             time / tickOOM,
             tickTime < 1000 ? "" : (tickTime < 999999 ? "k" : (tickTime  < 999999999 ? "m" : "") ),
             timeout / tickOOM,
             tickTime < 1000 ? "" : (tickTime < 999999 ? "k" : (tickTime  < 999999999 ? "m" : "") ),
             responses.size(),
             1000.0 * ( std::clock() - startTime ) / ((double) CLOCKS_PER_SEC));
    }

    // -- Check If Valid --
    if (knownFacts->contains(parent->fact, parent->factLength)) {
      printf("> %s\n", toString(*graph, *fringe, parent).c_str());
      responses.push_back(parent);
    }

    // -- Mutations --
    for (int indexToMutate = 0;
         indexToMutate < parent->factLength;
         ++indexToMutate) {  // for each index to mutate...
      const vector<edge>& mutations
        = graph->outgoingEdges(parent->fact[indexToMutate]);
//      printf("  mutating index %d; %lu children\n", indexToMutate, mutations.size());
      for(vector<edge>::const_iterator it = mutations.begin();
          it != mutations.end();
          ++it) {  // for each possible mutation on that index...
        if (it->type > 1) { continue; } // TODO(gabor) don't only do WordNet jumps
        // Add the state to the fringe
        fringe->push(parent, indexToMutate, 1, it->sink, 0, it->type);
      }
    }
  }

  printf("Search complete; %lu paths found\n", responses.size());
  return responses;
}

<|endoftext|>


<commit_before>/*
   Copyright (c) 2015, Andreas Fett. All rights reserved.
   Use of this source code is governed by a BSD-style
   license that can be found in the LICENSE file.
*/

#include <errno.h>
#include <inttypes.h>

#include <cassert>
#include <cstdlib>
#include <cstring>
#include <ostream>
#include <stdexcept>

#include "token-stream.h"
#include "utf8stream.h"

namespace {

bool is_ws(int c)
{
	return c == ' ' || c == '\t' || c == '\r' || c == '\n';
}

}

namespace jsonp {

// LCOV_EXCL_START
std::ostream & operator<<(std::ostream & os, Token::Type type)
{
#define CASE_TOKEN_TYPE(name) case name: os << # name; break
	switch (type) {
	CASE_TOKEN_TYPE(Token::INVALID);
	CASE_TOKEN_TYPE(Token::BEGIN_ARRAY);
	CASE_TOKEN_TYPE(Token::END_ARRAY);
	CASE_TOKEN_TYPE(Token::BEGIN_OBJECT);
	CASE_TOKEN_TYPE(Token::END_OBJECT);
	CASE_TOKEN_TYPE(Token::NAME_SEPARATOR);
	CASE_TOKEN_TYPE(Token::VALUE_SEPARATOR);
	CASE_TOKEN_TYPE(Token::TRUE_LITERAL);
	CASE_TOKEN_TYPE(Token::FALSE_LITERAL);
	CASE_TOKEN_TYPE(Token::NULL_LITERAL);
	CASE_TOKEN_TYPE(Token::STRING);
	CASE_TOKEN_TYPE(Token::NUMBER);
	}
#undef CASE_TOKEN_TYPE
	return os;
}
// LCOV_EXCL_STOP

TokenStream::TokenStream(Utf8Stream & stream)
:
	stream_(stream)
{ }

void TokenStream::scan()
{
	token.reset();

	int c;
	do {
		c = stream_.getc();
	} while (is_ws(c));

	if (c == int(Utf8Stream::SEOF)) {
		return;
	}

	if (stream_.state() == Utf8Stream::SBAD) {
		return;
	}

	try {
		(this->*select_scanner(c))();
	} catch (std::runtime_error const& e) {
		throw;
	}
}

TokenStream::scanner TokenStream::select_scanner(int c)
{
	scanner res(0);

	switch (c) {
	case '[': case '{': case ']':
	case '}': case ':': case ',':
		res = &TokenStream::scan_structural;
		break;
	case 't':
		res = &TokenStream::scan_true;
		break;
	case 'n':
		res = &TokenStream::scan_null;
		break;
	case 'f':
		res = &TokenStream::scan_false;
		break;
	case '"':
		res = &TokenStream::scan_string;
		break;
	case '-':
	case '0': case '1': case '2': case '3': case '4':
	case '5': case '6': case '7': case '8': case '9':
		c = '0';
		stream_.ungetc();
		res = &TokenStream::scan_number;
		break;
	default:
		c = 0;
		res = &TokenStream::invalid_token;
		break;
	}

	token.type = Token::Type(c);
	return res;
}

void TokenStream::invalid_token() { throw std::runtime_error("invalid token"); }
void TokenStream::scan_structural() { /* NOOP */ }
void TokenStream::scan_true() { scan_literal("true"); }
void TokenStream::scan_false() { scan_literal("false"); }
void TokenStream::scan_null() { scan_literal("null"); }

void TokenStream::scan_literal(const char *literal)
{
	for (const char *p(&literal[1]); *p; p++) {
		if (stream_.getc() != *p) {
			throw std::runtime_error(literal);
		}
	}
}

enum StringState {
	SREGULAR,
	SESCAPED,
	SUESCAPE,
	SDONES,
	// errors
	SREGULAR_INVALID,
	SESCAPED_INVALID,
	SUESCAPE_INVALID,
	SUESCAPE_SURROGATE,
	SUNTERMINATED,
	SZERO,
};

StringState scan_regular(int c, std::string & str)
{
	if (c == '"') {
		return SDONES;
	} else if (c == '\\') {
		return SESCAPED;
	} else if (c >= 0x0000 && c <= 0x001F) {
		// control char must be escaped
		return SREGULAR_INVALID;
	}

	str.push_back(c);
	return SREGULAR;
}

StringState scan_escaped(int c, std::string & str)
{
	switch (c) {
	case '\\': case '/': case '"': break;
	case 'b': c = 0x0008; break;
	case 'f': c = 0x000C; break;
	case 'n': c = 0x000A; break;
	case 'r': c = 0x000D; break;
	case 't': c = 0x0009; break;
	case 'u': return SUESCAPE;
	default:
		// invalid escape char
		return SESCAPED_INVALID;
	}

	str.push_back(c);
	return SREGULAR;
}

struct uescape {
public:
	uescape()
	:
		count_(0),
		value_(0)
	{ }

	StringState scan(int c, std::string & str)
	{
		value_ *= 0x10;
		if (c >= '0' && c <= '9') {
			value_ += c - '0';
		} else if (c >= 'a' && c <= 'f') {
			value_ += 0x0a + c - 'a';
		} else if (c >= 'A' && c <= 'F') {
			value_ += 0x0a + c - 'A';
		} else {
			return SUESCAPE_INVALID;
		}

		if (++count_ == 4) {
			StringState res(utf8encode(str));
			count_ = value_ = 0;
			return res;
		}

		return SUESCAPE;
	}

private:
	StringState utf8encode(std::string & str) const
	{
		if (value_ == 0x0000) {
			// ASCII 0
			return SZERO;
		} else if (value_ <= 0x007f) {
			str.push_back(value_);
		} else if (value_ <= 0x07ff) {
			str.push_back(0xc0 | (value_ >> 6));
			str.push_back(0x80 | (value_ & 0x3f));
		} else if (value_ >= 0xd800 && value_ <= 0xdfff) {
			// utf16 surrogate
			return SUESCAPE_SURROGATE;
		} else {
			str.push_back(0xe0 | (value_ >> 12));
			str.push_back(0x80 | ((value_ >> 6) & 0x3f));
			str.push_back(0x80 | (value_ & 0x3f));
		}

		return SREGULAR;
	}

	size_t count_;
	uint16_t value_;
};

void TokenStream::scan_string()
{
	StringState state(SREGULAR);
	uescape unicode;
	while (state != SDONES) {
		int c(stream_.getc());
		if (stream_.state() != Utf8Stream::SGOOD) {
			// unterminated string
			state = SUNTERMINATED;
		}

		switch (state) {
		case SREGULAR:
			state = scan_regular(c, token.str_value);
			break;
		case SESCAPED:
			state = scan_escaped(c, token.str_value);
			break;
		case SUESCAPE:
			state = unicode.scan(c, token.str_value);
			break;
		case SREGULAR_INVALID:
		case SESCAPED_INVALID:
		case SUESCAPE_INVALID:
		case SUESCAPE_SURROGATE:
		case SUNTERMINATED:
		case SZERO:
			token.str_value.clear();
			token.type = Token::INVALID;
			return;
		case SDONES:
			break;
		}
	}
}

// POSIX thread local locale setting.
struct auto_locale {
	auto_locale(const char *name)
	:
		locale_(newlocale(LC_ALL_MASK, name, 0)),
		saved_(uselocale(locale_))
	{ }

	~auto_locale()
	{
		uselocale(saved_);
		freelocale(locale_);
	}

	locale_t locale_;
	locale_t saved_;
};

bool make_int(const char *str, int64_t *res)
{
	errno = 0;
	char *endp(0);
	*res = strtoll(str, &endp, 10);
	if (*endp != '\0') {
		return false;
	}
	if (errno != 0) {
		return false;
	}
	return true;
}

bool make_float(const char *str, long double *res)
{
	errno = 0;
	char *endp(0);
	auto_locale lc("C");
	*res = strtold(str, &endp);
	if (*endp != '\0') {
		return false;
	}
	if (errno != 0) {
		return false;
	}
	return true;
}

enum NumberState {
	SSTART = 0,
	SMINUS,
	SINT_ZERO,
	SINT_DIGIT,
	SINT_DIGIT19,
	SDEC_POINT,
	SFRAC_DIGIT,
	SE,
	SE_PLUS,
	SE_MINUS,
	SE_DIGIT,
	SDONE,
	SERROR,
};

NumberState number_state(int c, NumberState state)
{
#define DIGIT19 "123456789"
#define DIGIT "0" DIGIT19
	struct {
		const char *match;
		NumberState state;
	} transitions[][4] = {
	/* SSTART       */ {{"-", SMINUS},   {"0", SINT_ZERO},  {DIGIT19, SINT_DIGIT19}, {0, SERROR}},
	/* SMINUS       */ {                 {"0", SINT_ZERO},  {DIGIT19, SINT_DIGIT19}, {0, SERROR}},
	/* SINT_ZERO    */ {{"eE", SE},      {".", SDEC_POINT},                          {0, SDONE} },
	/* SINT_DIGIT   */ {{"eE", SE},      {".", SDEC_POINT}, {DIGIT, SINT_DIGIT},     {0, SDONE} },
	/* SINT_DIGIT19 */ {{"eE", SE},      {".", SDEC_POINT}, {DIGIT, SINT_DIGIT},     {0, SDONE} },
	/* SDEC_POINT   */ {{"eE", SE},                         {DIGIT, SFRAC_DIGIT},    {0, SERROR}},
	/* SFRAC_DIGIT  */ {{"eE", SE},                         {DIGIT, SFRAC_DIGIT},    {0, SDONE} },
	/* SE           */ {{"-", SE_MINUS}, {"+", SE_PLUS},    {DIGIT, SE_DIGIT},       {0, SERROR}},
	/* SE_PLUS      */ {                                    {DIGIT, SE_DIGIT},       {0, SERROR}},
	/* SE_MINUS     */ {                                    {DIGIT, SE_DIGIT},       {0, SERROR}},
	/* SE_DIGIT     */ {                                    {DIGIT, SE_DIGIT},       {0, SDONE} },
	};

	for (size_t t(0); true; ++t) {
		const char *match(transitions[state][t].match);
		if (!match || strchr(match, c)) {
			return transitions[state][t].state;
		}
	}

	return SERROR;
}

Token::NumberType validate_number(Utf8Stream & stream, char *buf, size_t size)
{
	NumberState state(SSTART);
	Token::NumberType res(Token::INT);
	size_t i(0);
	for (;;) {
		int c(stream.getc());
		state = number_state(c, state);

		switch (state) {
		case SSTART:
			break;
		case SDEC_POINT:
		case SE:
			res = Token::FLOAT;
			// fallthrough
		case SMINUS:
		case SINT_ZERO:
		case SINT_DIGIT:
		case SINT_DIGIT19:
		case SFRAC_DIGIT:
		case SE_MINUS:
		case SE_PLUS:
		case SE_DIGIT:
			buf[i] = c;
			if (++i == size) {
				buf[i - 1] = '\0';
				return Token::NONE;
			}
			break;
		case SERROR:
			res = Token::NONE;
			// fallthrough
		case SDONE:
			buf[i] = '\0';
			stream.ungetc();
			return res;
		}
	}

	return Token::NONE;
}

void TokenStream::scan_number()
{
	char buf[1024];
	token.number_type = validate_number(stream_, buf, sizeof(buf));
	switch (token.number_type) {
	case Token::INT:
		if (!make_int(buf, &token.int_value)) {
			token.type = Token::INVALID;
			token.number_type = Token::NONE;
			token.int_value = 0;
			return;
		}
		break;
	case Token::FLOAT:
		if (!make_float(buf, &token.float_value)) {
			token.type = Token::INVALID;
			token.number_type = Token::NONE;
			token.float_value = 0;
			return;
		}
		break;
	case Token::NONE:
		token.type = Token::INVALID;
		break;
	}
}

}
<commit_msg>TokenStream: reset token on error<commit_after>/*
   Copyright (c) 2015, Andreas Fett. All rights reserved.
   Use of this source code is governed by a BSD-style
   license that can be found in the LICENSE file.
*/

#include <errno.h>
#include <inttypes.h>

#include <cassert>
#include <cstdlib>
#include <cstring>
#include <ostream>
#include <stdexcept>

#include "token-stream.h"
#include "utf8stream.h"

namespace {

bool is_ws(int c)
{
	return c == ' ' || c == '\t' || c == '\r' || c == '\n';
}

}

namespace jsonp {

// LCOV_EXCL_START
std::ostream & operator<<(std::ostream & os, Token::Type type)
{
#define CASE_TOKEN_TYPE(name) case name: os << # name; break
	switch (type) {
	CASE_TOKEN_TYPE(Token::INVALID);
	CASE_TOKEN_TYPE(Token::BEGIN_ARRAY);
	CASE_TOKEN_TYPE(Token::END_ARRAY);
	CASE_TOKEN_TYPE(Token::BEGIN_OBJECT);
	CASE_TOKEN_TYPE(Token::END_OBJECT);
	CASE_TOKEN_TYPE(Token::NAME_SEPARATOR);
	CASE_TOKEN_TYPE(Token::VALUE_SEPARATOR);
	CASE_TOKEN_TYPE(Token::TRUE_LITERAL);
	CASE_TOKEN_TYPE(Token::FALSE_LITERAL);
	CASE_TOKEN_TYPE(Token::NULL_LITERAL);
	CASE_TOKEN_TYPE(Token::STRING);
	CASE_TOKEN_TYPE(Token::NUMBER);
	}
#undef CASE_TOKEN_TYPE
	return os;
}
// LCOV_EXCL_STOP

TokenStream::TokenStream(Utf8Stream & stream)
:
	stream_(stream)
{ }

void TokenStream::scan()
{
	token.reset();

	int c;
	do {
		c = stream_.getc();
	} while (is_ws(c));

	if (c == int(Utf8Stream::SEOF)) {
		return;
	}

	if (stream_.state() == Utf8Stream::SBAD) {
		return;
	}

	try {
		(this->*select_scanner(c))();
	} catch (std::runtime_error const& e) {
		throw;
	}
}

TokenStream::scanner TokenStream::select_scanner(int c)
{
	scanner res(0);

	switch (c) {
	case '[': case '{': case ']':
	case '}': case ':': case ',':
		res = &TokenStream::scan_structural;
		break;
	case 't':
		res = &TokenStream::scan_true;
		break;
	case 'n':
		res = &TokenStream::scan_null;
		break;
	case 'f':
		res = &TokenStream::scan_false;
		break;
	case '"':
		res = &TokenStream::scan_string;
		break;
	case '-':
	case '0': case '1': case '2': case '3': case '4':
	case '5': case '6': case '7': case '8': case '9':
		c = '0';
		stream_.ungetc();
		res = &TokenStream::scan_number;
		break;
	default:
		c = 0;
		res = &TokenStream::invalid_token;
		break;
	}

	token.type = Token::Type(c);
	return res;
}

void TokenStream::invalid_token() { throw std::runtime_error("invalid token"); }
void TokenStream::scan_structural() { /* NOOP */ }
void TokenStream::scan_true() { scan_literal("true"); }
void TokenStream::scan_false() { scan_literal("false"); }
void TokenStream::scan_null() { scan_literal("null"); }

void TokenStream::scan_literal(const char *literal)
{
	for (const char *p(&literal[1]); *p; p++) {
		if (stream_.getc() != *p) {
			throw std::runtime_error(literal);
		}
	}
}

enum StringState {
	SREGULAR,
	SESCAPED,
	SUESCAPE,
	SDONES,
	// errors
	SREGULAR_INVALID,
	SESCAPED_INVALID,
	SUESCAPE_INVALID,
	SUESCAPE_SURROGATE,
	SUNTERMINATED,
	SZERO,
};

StringState scan_regular(int c, std::string & str)
{
	if (c == '"') {
		return SDONES;
	} else if (c == '\\') {
		return SESCAPED;
	} else if (c >= 0x0000 && c <= 0x001F) {
		// control char must be escaped
		return SREGULAR_INVALID;
	}

	str.push_back(c);
	return SREGULAR;
}

StringState scan_escaped(int c, std::string & str)
{
	switch (c) {
	case '\\': case '/': case '"': break;
	case 'b': c = 0x0008; break;
	case 'f': c = 0x000C; break;
	case 'n': c = 0x000A; break;
	case 'r': c = 0x000D; break;
	case 't': c = 0x0009; break;
	case 'u': return SUESCAPE;
	default:
		// invalid escape char
		return SESCAPED_INVALID;
	}

	str.push_back(c);
	return SREGULAR;
}

struct uescape {
public:
	uescape()
	:
		count_(0),
		value_(0)
	{ }

	StringState scan(int c, std::string & str)
	{
		value_ *= 0x10;
		if (c >= '0' && c <= '9') {
			value_ += c - '0';
		} else if (c >= 'a' && c <= 'f') {
			value_ += 0x0a + c - 'a';
		} else if (c >= 'A' && c <= 'F') {
			value_ += 0x0a + c - 'A';
		} else {
			return SUESCAPE_INVALID;
		}

		if (++count_ == 4) {
			StringState res(utf8encode(str));
			count_ = value_ = 0;
			return res;
		}

		return SUESCAPE;
	}

private:
	StringState utf8encode(std::string & str) const
	{
		if (value_ == 0x0000) {
			// ASCII 0
			return SZERO;
		} else if (value_ <= 0x007f) {
			str.push_back(value_);
		} else if (value_ <= 0x07ff) {
			str.push_back(0xc0 | (value_ >> 6));
			str.push_back(0x80 | (value_ & 0x3f));
		} else if (value_ >= 0xd800 && value_ <= 0xdfff) {
			// utf16 surrogate
			return SUESCAPE_SURROGATE;
		} else {
			str.push_back(0xe0 | (value_ >> 12));
			str.push_back(0x80 | ((value_ >> 6) & 0x3f));
			str.push_back(0x80 | (value_ & 0x3f));
		}

		return SREGULAR;
	}

	size_t count_;
	uint16_t value_;
};

void TokenStream::scan_string()
{
	StringState state(SREGULAR);
	uescape unicode;
	while (state != SDONES) {
		int c(stream_.getc());
		if (stream_.state() != Utf8Stream::SGOOD) {
			// unterminated string
			state = SUNTERMINATED;
		}

		switch (state) {
		case SREGULAR:
			state = scan_regular(c, token.str_value);
			break;
		case SESCAPED:
			state = scan_escaped(c, token.str_value);
			break;
		case SUESCAPE:
			state = unicode.scan(c, token.str_value);
			break;
		case SREGULAR_INVALID:
		case SESCAPED_INVALID:
		case SUESCAPE_INVALID:
		case SUESCAPE_SURROGATE:
		case SUNTERMINATED:
		case SZERO:
			token.reset();
			return;
		case SDONES:
			break;
		}
	}
}

// POSIX thread local locale setting.
struct auto_locale {
	auto_locale(const char *name)
	:
		locale_(newlocale(LC_ALL_MASK, name, 0)),
		saved_(uselocale(locale_))
	{ }

	~auto_locale()
	{
		uselocale(saved_);
		freelocale(locale_);
	}

	locale_t locale_;
	locale_t saved_;
};

bool make_int(const char *str, int64_t *res)
{
	errno = 0;
	char *endp(0);
	*res = strtoll(str, &endp, 10);
	if (*endp != '\0') {
		return false;
	}
	if (errno != 0) {
		return false;
	}
	return true;
}

bool make_float(const char *str, long double *res)
{
	errno = 0;
	char *endp(0);
	auto_locale lc("C");
	*res = strtold(str, &endp);
	if (*endp != '\0') {
		return false;
	}
	if (errno != 0) {
		return false;
	}
	return true;
}

enum NumberState {
	SSTART = 0,
	SMINUS,
	SINT_ZERO,
	SINT_DIGIT,
	SINT_DIGIT19,
	SDEC_POINT,
	SFRAC_DIGIT,
	SE,
	SE_PLUS,
	SE_MINUS,
	SE_DIGIT,
	SDONE,
	SERROR,
};

NumberState number_state(int c, NumberState state)
{
#define DIGIT19 "123456789"
#define DIGIT "0" DIGIT19
	struct {
		const char *match;
		NumberState state;
	} transitions[][4] = {
	/* SSTART       */ {{"-", SMINUS},   {"0", SINT_ZERO},  {DIGIT19, SINT_DIGIT19}, {0, SERROR}},
	/* SMINUS       */ {                 {"0", SINT_ZERO},  {DIGIT19, SINT_DIGIT19}, {0, SERROR}},
	/* SINT_ZERO    */ {{"eE", SE},      {".", SDEC_POINT},                          {0, SDONE} },
	/* SINT_DIGIT   */ {{"eE", SE},      {".", SDEC_POINT}, {DIGIT, SINT_DIGIT},     {0, SDONE} },
	/* SINT_DIGIT19 */ {{"eE", SE},      {".", SDEC_POINT}, {DIGIT, SINT_DIGIT},     {0, SDONE} },
	/* SDEC_POINT   */ {{"eE", SE},                         {DIGIT, SFRAC_DIGIT},    {0, SERROR}},
	/* SFRAC_DIGIT  */ {{"eE", SE},                         {DIGIT, SFRAC_DIGIT},    {0, SDONE} },
	/* SE           */ {{"-", SE_MINUS}, {"+", SE_PLUS},    {DIGIT, SE_DIGIT},       {0, SERROR}},
	/* SE_PLUS      */ {                                    {DIGIT, SE_DIGIT},       {0, SERROR}},
	/* SE_MINUS     */ {                                    {DIGIT, SE_DIGIT},       {0, SERROR}},
	/* SE_DIGIT     */ {                                    {DIGIT, SE_DIGIT},       {0, SDONE} },
	};

	for (size_t t(0); true; ++t) {
		const char *match(transitions[state][t].match);
		if (!match || strchr(match, c)) {
			return transitions[state][t].state;
		}
	}

	return SERROR;
}

Token::NumberType validate_number(Utf8Stream & stream, char *buf, size_t size)
{
	NumberState state(SSTART);
	Token::NumberType res(Token::INT);
	size_t i(0);
	for (;;) {
		int c(stream.getc());
		state = number_state(c, state);

		switch (state) {
		case SSTART:
			break;
		case SDEC_POINT:
		case SE:
			res = Token::FLOAT;
			// fallthrough
		case SMINUS:
		case SINT_ZERO:
		case SINT_DIGIT:
		case SINT_DIGIT19:
		case SFRAC_DIGIT:
		case SE_MINUS:
		case SE_PLUS:
		case SE_DIGIT:
			buf[i] = c;
			if (++i == size) {
				buf[i - 1] = '\0';
				return Token::NONE;
			}
			break;
		case SERROR:
			res = Token::NONE;
			// fallthrough
		case SDONE:
			buf[i] = '\0';
			stream.ungetc();
			return res;
		}
	}

	return Token::NONE;
}

void TokenStream::scan_number()
{
	char buf[1024];
	token.number_type = validate_number(stream_, buf, sizeof(buf));
	switch (token.number_type) {
	case Token::INT:
		if (!make_int(buf, &token.int_value)) {
			token.reset();
			return;
		}
		break;
	case Token::FLOAT:
		if (!make_float(buf, &token.float_value)) {
			token.reset();
			return;
		}
		break;
	case Token::NONE:
		token.reset();
		break;
	}
}

}
<|endoftext|>


<commit_before>/*
 * Copyright 2010-2011 Andrea Nall
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <vector>
#include <sudoku/Solver.h>
#include <sudoku/Puzzle.h>
#include <sudoku/CellSet.h>
#include <sudoku/Cell.h>

#include <stdio.h>
#include <assert.h>

namespace sudoku {
    static int phase1_alone(Ref<Puzzle> pz, CellSet *cs);

#ifdef DEBUG
    const char *Solver::solveMethod::_empty = "";
#endif

    static const Solver::solveMethod methods[] = {
        Solver::solveMethod(phase1_alone, "only poss"),
        0
    };

    Solver::Solver(Ref<Puzzle> pz, bool allowRecurse, SolverSettings settings, Ref<SolverCallbacks> cb ) : _iters(0), _bfIters(0), _solutionCt(0), _settings(settings), _allowRecurse(allowRecurse), _callbacks(cb) {
        _pz = new Puzzle(pz);
    }

    Solver::Solver(const Solver &sv, Ref<Puzzle> pz ) : _pz(pz), _iters(sv._iters), _bfIters(sv._bfIters), _solutionCt(sv._solutionCt), _settings(sv._settings), _allowRecurse(sv._allowRecurse), _callbacks(sv._callbacks) {
    }

    void Solver::solve() {
        if ( _pz->solved() || ! _pz->solvable() ) return;
        solveSingle();
        if ( _pz->solved() ) {
            _solutionCt++;
            _solutions.push_back(_pz);
            if ( _callbacks )
                _callbacks->gotSolution( _pz );
        }
        if ( _pz->solved() || ! _pz->solvable() ) return;
        if ( _allowRecurse && _bfIters < _settings.bruteIterLimit && _solutionCt < _settings.maxSolutions )
            solveBrute();
    }

    /* UNUSED>
    static void copyValues(Ref<Puzzle> to, Ref<Puzzle> from) {
        assert( to->size() == from->size() );
        std::vector<Cell *> &cells = from->cells();
        std::vector<Cell *>::iterator it;
        for ( it = cells.begin(); it < cells.end(); it++ ) {
            Cell *fc = *it;
            Cell *tc = to->cell(fc->position());
            if ( fc->value() == 0 ) continue;
            if ( tc->value() ) continue;
            tc->value(fc->value());
        }
    } */

    void Solver::solveBrute() {
        if ( _bfIters % 100 == 0 ) {
            printf("Brute iter %i / %i\n",_bfIters,_settings.bruteIterLimit);
        }
        _bfIters++;
        // find an unset cell with the fewest options!
        int sz = _pz->size();
        int ct = sz + 1;
        Cell *cl = 0;
        std::vector<Cell *> &cells = _pz->cells();
        std::vector<Cell *>::iterator it;
        for ( it = cells.begin(); it < cells.end(); it++ ) {
            if ( (*it)->value() != 0 ) continue;
            int ict = (*it)->pencilCount();
            if ( ict < ct ) {
                ct = ict;
                cl = *it;
            }
        }
        if ( ct == sz + 1 ) return;
        for ( int i = 1; i <= sz; i++ ) {
            if ( cl->pencil(i) == false ) continue;
            Ref<Puzzle> npz = new Puzzle( _pz );
            npz->cell(cl->position())->value(i);
            if ( npz->solved() ) {
                _solutionCt++;
                _solutions.push_back(npz);
                if ( _callbacks )
                    _callbacks->gotSolution( npz );
                return; // If we're solved here, there's probably not another solution
            } else if ( npz->solvable() ) {
                Solver slv(*this,npz);
                slv.solve();
                _solutions.insert( _solutions.end(), slv._solutions.begin(), slv._solutions.end() );
                _iters = slv._iters;
                _bfIters = slv._bfIters;
                _solutionCt = slv._solutionCt;
            }
            if ( _solutionCt >= _settings.maxSolutions ) return;
        }
    }

    void Solver::solveSingle() {
        int iters = 0;
        int dn = -1;
        int idn = -1;
        _pz->ready(true);
        while ( dn != 0 && iters < _settings.iterLimit ) {
            dn = 0;
            const Solver::solveMethod *mthd = methods;
            while ( mthd->exists() && iters < _settings.iterLimit ) {
                do {
                    idn = mthd->solveUsing(_pz);
                    if ( _pz->solved() || ! _pz->solvable() ) return;
                    dn += idn;
                    iters++;
                    _iters++;
                } while (idn != 0 && iters < _settings.iterLimit );
                mthd++;
            }
        }
    }

    Solver::solveMethod::solveMethod(solveMethodSub ms, const char *name) : _mthd(ms) {
#ifdef DEBUG
        _name = name;
#endif
    }

#ifdef DEBUG
    const char *Solver::solveMethod::name() const { return _name; }
#endif
    bool Solver::solveMethod::exists() const { return _mthd != NULL; }

    int Solver::solveMethod::solveUsing(Ref<Puzzle> pz) const {
        std::vector<CellSet *> &css = pz->cellsets();
        std::vector<CellSet *>::iterator it;
        int ct = 0;
        for ( it = css.begin() ; it < css.end(); it++ )
            ct += _mthd(pz,*it);
        return ct;
    }

    int phase1_alone(Ref<Puzzle> pz, CellSet *cs) {
        std::vector<Position>::iterator it;
        unsigned int sz = pz->size();
        int *cts = new int[sz];
        Cell **cls = new Cell*[sz];
        Cell **cla = new Cell*[sz];
        memset(cts,0,sizeof(int) * sz);
        memset(cls,0,sizeof(Cell *) * sz);
        memset(cla,0,sizeof(Cell *) * sz);
        assert ( sz == cs->size() && "Cellset is the wrong length!" );
        for ( it = cs->begin(); it < cs->end(); it++ ) {
            Cell *ccl = pz->cell(*it);
            int ct = 0;
            int v = 0;

            // This is a gaurd against any problems!
            if ( ( v = ccl->value() ) != 0 ) {
                cts[v-1] = 100;
                continue;
            }

            for ( unsigned int i = 1; i <= sz; i++ ) {
                if ( ccl->pencil(i) ) {
                    v = i;
                    ct++;

                    cts[i-1]++;
                    cls[i-1] = ccl;
                }
            }
            if ( ct == 1 ) {
                cts[v-1]++;
                cla[v-1] = ccl;
            }
        }
        int ct = 0;
        int lct = 0;
        for ( unsigned int i = 0; i < sz; i++ ) {
            lct = ct;
            if ( cla[i] != 0 && cla[i]->value() == 0 ) {
                assert( cla[i]->value() == 0 && "Tried setting an already-set cell" );
                cla[i]->value(i+1);
                ct++;
            }
            if ( cts[i] == 1 && cls[i]->value() == 0 ) {
                assert( cls[i]->value() == 0 && "Tried setting an already set cell" );
                cls[i]->value(i+1);
                ct++;
            }
        }
        delete[] cts;
        delete[] cls;
        delete[] cla;
        return ct;
    }
}
<commit_msg>Allow puzzles over 99 in size, allow cellsets smaller then the puzzle size.<commit_after>/*
 * Copyright 2010-2011 Andrea Nall
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <vector>
#include <sudoku/Solver.h>
#include <sudoku/Puzzle.h>
#include <sudoku/CellSet.h>
#include <sudoku/Cell.h>

#include <stdio.h>
#include <assert.h>

namespace sudoku {
    static int phase1_alone(Ref<Puzzle> pz, CellSet *cs);

#ifdef DEBUG
    const char *Solver::solveMethod::_empty = "";
#endif

    static const Solver::solveMethod methods[] = {
        Solver::solveMethod(phase1_alone, "only poss"),
        0
    };

    Solver::Solver(Ref<Puzzle> pz, bool allowRecurse, SolverSettings settings, Ref<SolverCallbacks> cb ) : _iters(0), _bfIters(0), _solutionCt(0), _settings(settings), _allowRecurse(allowRecurse), _callbacks(cb) {
        _pz = new Puzzle(pz);
    }

    Solver::Solver(const Solver &sv, Ref<Puzzle> pz ) : _pz(pz), _iters(sv._iters), _bfIters(sv._bfIters), _solutionCt(sv._solutionCt), _settings(sv._settings), _allowRecurse(sv._allowRecurse), _callbacks(sv._callbacks) {
    }

    void Solver::solve() {
        if ( _pz->solved() || ! _pz->solvable() ) return;
        solveSingle();
        if ( _pz->solved() ) {
            _solutionCt++;
            _solutions.push_back(_pz);
            if ( _callbacks )
                _callbacks->gotSolution( _pz );
        }
        if ( _pz->solved() || ! _pz->solvable() ) return;
        if ( _allowRecurse && _bfIters < _settings.bruteIterLimit && _solutionCt < _settings.maxSolutions )
            solveBrute();
    }

    /* UNUSED>
    static void copyValues(Ref<Puzzle> to, Ref<Puzzle> from) {
        assert( to->size() == from->size() );
        std::vector<Cell *> &cells = from->cells();
        std::vector<Cell *>::iterator it;
        for ( it = cells.begin(); it < cells.end(); it++ ) {
            Cell *fc = *it;
            Cell *tc = to->cell(fc->position());
            if ( fc->value() == 0 ) continue;
            if ( tc->value() ) continue;
            tc->value(fc->value());
        }
    } */

    void Solver::solveBrute() {
        if ( _bfIters % 100 == 0 ) {
            printf("Brute iter %i / %i\n",_bfIters,_settings.bruteIterLimit);
        }
        _bfIters++;
        // find an unset cell with the fewest options!
        int sz = _pz->size();
        int ct = sz + 1;
        Cell *cl = 0;
        std::vector<Cell *> &cells = _pz->cells();
        std::vector<Cell *>::iterator it;
        for ( it = cells.begin(); it < cells.end(); it++ ) {
            if ( (*it)->value() != 0 ) continue;
            int ict = (*it)->pencilCount();
            if ( ict < ct ) {
                ct = ict;
                cl = *it;
            }
        }
        if ( ct == sz + 1 ) return;
        for ( int i = 1; i <= sz; i++ ) {
            if ( cl->pencil(i) == false ) continue;
            Ref<Puzzle> npz = new Puzzle( _pz );
            npz->cell(cl->position())->value(i);
            if ( npz->solved() ) {
                _solutionCt++;
                _solutions.push_back(npz);
                if ( _callbacks )
                    _callbacks->gotSolution( npz );
                return; // If we're solved here, there's probably not another solution
            } else if ( npz->solvable() ) {
                Solver slv(*this,npz);
                slv.solve();
                _solutions.insert( _solutions.end(), slv._solutions.begin(), slv._solutions.end() );
                _iters = slv._iters;
                _bfIters = slv._bfIters;
                _solutionCt = slv._solutionCt;
            }
            if ( _solutionCt >= _settings.maxSolutions ) return;
        }
    }

    void Solver::solveSingle() {
        int iters = 0;
        int dn = -1;
        int idn = -1;
        _pz->ready(true);
        while ( dn != 0 && iters < _settings.iterLimit ) {
            dn = 0;
            const Solver::solveMethod *mthd = methods;
            while ( mthd->exists() && iters < _settings.iterLimit ) {
                do {
                    idn = mthd->solveUsing(_pz);
                    if ( _pz->solved() || ! _pz->solvable() ) return;
                    dn += idn;
                    iters++;
                    _iters++;
                } while (idn != 0 && iters < _settings.iterLimit );
                mthd++;
            }
        }
    }

    Solver::solveMethod::solveMethod(solveMethodSub ms, const char *name) : _mthd(ms) {
#ifdef DEBUG
        _name = name;
#endif
    }

#ifdef DEBUG
    const char *Solver::solveMethod::name() const { return _name; }
#endif
    bool Solver::solveMethod::exists() const { return _mthd != NULL; }

    int Solver::solveMethod::solveUsing(Ref<Puzzle> pz) const {
        std::vector<CellSet *> &css = pz->cellsets();
        std::vector<CellSet *>::iterator it;
        int ct = 0;
        for ( it = css.begin() ; it < css.end(); it++ )
            ct += _mthd(pz,*it);
        return ct;
    }

    int phase1_alone(Ref<Puzzle> pz, CellSet *cs) {
        std::vector<Position>::iterator it;
        unsigned int sz = pz->size();
        int *cts = new int[sz];
        Cell **cls = new Cell*[sz];
        Cell **cla = new Cell*[sz];
        memset(cts,0,sizeof(int) * sz);
        memset(cls,0,sizeof(Cell *) * sz);
        memset(cla,0,sizeof(Cell *) * sz);
        if ( sz != cs->size() ) return 0;
        for ( it = cs->begin(); it < cs->end(); it++ ) {
            Cell *ccl = pz->cell(*it);
            int ct = 0;
            int v = 0;

            // This is a gaurd against any problems!
            if ( ( v = ccl->value() ) != 0 ) {
                cts[v-1] = sz + 1;
                continue;
            }

            for ( unsigned int i = 1; i <= sz; i++ ) {
                if ( ccl->pencil(i) ) {
                    v = i;
                    ct++;

                    cts[i-1]++;
                    cls[i-1] = ccl;
                }
            }
            if ( ct == 1 ) {
                cts[v-1]++;
                cla[v-1] = ccl;
            }
        }
        int ct = 0;
        int lct = 0;
        for ( unsigned int i = 0; i < sz; i++ ) {
            lct = ct;
            if ( cla[i] != 0 && cla[i]->value() == 0 ) {
                assert( cla[i]->value() == 0 && "Tried setting an already-set cell" );
                cla[i]->value(i+1);
                ct++;
            }
            if ( cts[i] == 1 && cls[i]->value() == 0 ) {
                assert( cls[i]->value() == 0 && "Tried setting an already set cell" );
                cls[i]->value(i+1);
                ct++;
            }
        }
        delete[] cts;
        delete[] cls;
        delete[] cla;
        return ct;
    }
}
<|endoftext|>


<commit_before>/*
 ============================================================================
 Name        : SampleSort
 Author      : Sebastian Schmidt, Lars Gottesbüren
 Version     :
 Copyright   : MIT License
 Description : Test the SampleSort algorithm smoothly and thoroughly.
 ============================================================================
 */

#include "mpi.h"
#include "SampleSort.h"
#include "Random.h"
#include "GatherSortSamplesStrategy.h"
#include "RecursiveSortSamplesStrategy.h"
#include "SortSamplesStrategy.h"
#include "SampleSortParams.h"
#include "SampleSizeStrategy.h"
#include "LogSampleSizeStrategy.h"
#include "RootSampleSizeStrategy.h"
#include "Debug.h"
#include "KWayMerge.h"

#include <math.h>
#include <iostream>
#include <cstdlib>
#include <vector>
#include <random>
#include <chrono>
#include <algorithm>
#include <thread>

using namespace std;
using namespace MPI;

const int TEST_DATA_SIZE = 50;

void generateRandomData(vector<int> &data, int minMax) {
	default_random_engine randomGenerator(getSeed());
	uniform_int_distribution<int> randomDistribution(-data.size() * minMax,
			data.size() * minMax);

	for (int i = 0; i < data.capacity(); i++) {
		data[i] = randomDistribution(randomGenerator);
		//cout << data[i] << endl;
	}
}

template<typename T>
bool checkSorted(vector<T> &array, int mpiRank, int mpiSize) {
	int size = array.size() * sizeof(T);
	vector<int> gatheredSizes;

	if (mpiRank == 0) {
		gatheredSizes.resize(mpiSize);
	}

	COMM_WORLD.Gather(&size, 1, MPI::INT, gatheredSizes.data(), 1, MPI::INT, 0);

	vector<T> allData;
	vector<int> offsets;

	if (mpiRank == 0) {
		offsets.resize(mpiSize);
		offsets[0] = 0;

		for (int i = 1; i < mpiSize; i++) {
			offsets[i] = gatheredSizes[i - 1] + offsets[i - 1];
		}

		allData.resize(
				(offsets[mpiSize - 1] + gatheredSizes[mpiSize - 1])
						/ sizeof(T));
	}

	COMM_WORLD.Gatherv(array.data(), array.size() * sizeof(T), MPI::BYTE,
			allData.data(), gatheredSizes.data(), offsets.data(), MPI::BYTE, 0);

	if (mpiRank == 0) {
		for (int i = 1; i < allData.size(); i++) {
			if (allData[i - 1] > allData[i]) {
				cout << "Sorting failed!" << endl;
				return false;
			}
		}

		//cout << "Sorting correct!" << endl;
		return true;
	}

	return true;
}

unsigned long runTest(int recursiveThreshold, bool withPresort, int inputSize) {
	int mpiSize = COMM_WORLD.Get_size();
	int mpiRank = COMM_WORLD.Get_rank();

	LogSampleSizeStrategy sss(6);
	//RootSampleSizeStrategy sss(2, 1);
	SampleSortParams params(mpiRank, mpiSize, 0, withPresort, -1, sss);
	// GatherSortSamplesStrategy sortSamplesStrategy;
	RecursiveSortSamplesStrategy<int> sortSamplesStrategy(recursiveThreshold);
	SampleSort<int> sorter(params, sortSamplesStrategy);
	vector<int> data(inputSize);
	generateRandomData(data, mpiSize);

	COMM_WORLD.Barrier();
	unsigned long start =
			chrono::high_resolution_clock::now().time_since_epoch().count();

	vector<int> result;
	sorter.sort(data, result, inputSize / mpiSize);

	unsigned long end =
			chrono::high_resolution_clock::now().time_since_epoch().count();
	COMM_WORLD.Barrier();

	unsigned long maxTime;
	unsigned long localTime = end - start;
	COMM_WORLD.Reduce(&localTime, &maxTime, 1, MPI::UNSIGNED_LONG, MPI::MAX, 0);

	double time = maxTime;
	time *= chrono::high_resolution_clock::period::type::num;
	time /= chrono::high_resolution_clock::period::type::den;

	if (!checkSorted(result, mpiRank, mpiSize)) {
		throw runtime_error("Result not sorted!");
	}

	if (mpiRank == 0) {
		//cout << "Sorting took " << (time * 1e6) << "us" << endl;
	}

	return time * 1e6;
}

unsigned long runStdSort(int recursiveThreshold, bool withPresort,
		int inputSize) {
	int mpiSize = COMM_WORLD.Get_size();
	int mpiRank = COMM_WORLD.Get_rank();

	if (mpiRank == 0) {
		vector<int> data(inputSize);
		generateRandomData(data, mpiSize);

		unsigned long start =
				chrono::high_resolution_clock::now().time_since_epoch().count();

		std::sort(data.begin(), data.end());

		unsigned long end =
				chrono::high_resolution_clock::now().time_since_epoch().count();

		unsigned long localTime = end - start;

		double time = localTime;
		time *= chrono::high_resolution_clock::period::type::num;
		time /= chrono::high_resolution_clock::period::type::den;

		if (mpiRank == 0) {
			//cout << "Sorting took " << (time * 1e6) << "us" << endl;
		}

		return time * 1e6;
	}

	return 0;
}

bool testAllEqualValue(int recursive_threshold, double value) {
	int mpiSize = COMM_WORLD.Get_size();
	int mpiRank = COMM_WORLD.Get_rank();

	vector<double> data(TEST_DATA_SIZE);
	for (vector<double>::iterator it = data.begin(); it != data.end(); it++) {
		*it = value;
	}

	LogSampleSizeStrategy sss(10);
	SampleSortParams params(mpiRank, mpiSize, 0, true, -1, sss);
	RecursiveSortSamplesStrategy<double> sortSamplesStrategy(
			recursive_threshold);
	SampleSort<double> sorter(params, sortSamplesStrategy);
	vector<double> results;
	sorter.sort(data, results, TEST_DATA_SIZE * mpiSize);
	return checkSorted(results, mpiRank, mpiSize);
}

unsigned long runTests(const int warmUp, const int runCount,
		int recursiveThreshold, bool withPresort, int inputSize,
		unsigned long test(int, bool, int)) {
	int mpiSize = COMM_WORLD.Get_size();
	int mpiRank = COMM_WORLD.Get_rank();
	vector<unsigned long> times;

	for (int i = 0; i < warmUp; i++) {
		if (mpiRank == 0 && (i % 50 == 0 || i == warmUp - 1)) {
			cout << "Warm up " << (i + 1) << "/" << warmUp << endl;
		}

		COMM_WORLD.Barrier();
		test(recursiveThreshold, withPresort, inputSize);
	}

	for (int i = 0; i < runCount; i++) {
		if (mpiRank == 0 && (i % 50 == 0 || i == runCount - 1)) {
			cout << "Running test no " << (i + 1) << "/" << runCount
					<< " with recursiveThreshold = " << recursiveThreshold
					<< " and with" << (withPresort ? "" : "out")
					<< " presort and with inputSize = " << inputSize << endl;
		}

		COMM_WORLD.Barrier();
		times.push_back(test(recursiveThreshold, withPresort, inputSize));
	}

	sort(times.begin(), times.end());
	unsigned long median = times[times.size() / 2];

	if (mpiRank == 0) {
		//cout << "Sorting time median = " << median << "us" << endl;
	}

	return median;
}

int main(int argc, char *argv[]) {
	Init(argc, argv);

	int mpiSize = COMM_WORLD.Get_size();
	int mpiRank = COMM_WORLD.Get_rank();

	//testAllEqualValue(50, 456.345634756);
	unsigned concurrentThreadsSupported = thread::hardware_concurrency();
	cout << mpiRank << ": concurrentThreadsSupported = "
			<< concurrentThreadsSupported << endl;

	vector<int> thresholds;
	vector<int> inputSizes;
	vector<unsigned long> ourMedians;
	vector<unsigned long> stdMedians;
	const int repetitions = 100;

	//thresholds.push_back(0);
	//thresholds.push_back(1);
	//thresholds.push_back(2);
	//thresholds.push_back(3);
	//thresholds.push_back(6);
	//thresholds.push_back(10);
	//thresholds.push_back(20);
	//thresholds.push_back(40);
	thresholds.push_back(80);
	//thresholds.push_back(160);
	//thresholds.push_back(320);
	thresholds.push_back(1 << 30);

	//for (int i = 0; i < 23; i++) {
	for (int i = 0; i < 13; i++) {
		inputSizes.push_back(1 << i);
	}

	COMM_WORLD.Barrier();

	for (int size : inputSizes) {
		if (mpiRank == 0) {
			cout << " ====== TESTING STD::SORT  ====== " << endl;
		}

		stdMedians.push_back(
				runTests(10, repetitions, -1, false, size, runStdSort));

		if (mpiRank == 0) {
			cout << " ====== TESTING SAMPLESORT ====== " << endl;
		}

		for (int i = 0; i < thresholds.size(); i++) {
			if (mpiRank == 0) {
				cout << " ====== ROUND " << (i + 1) << "/" << thresholds.size()
						<< " ====== " << endl;
			}

			ourMedians.push_back(
					runTests(10, repetitions, thresholds[i], true, size,
							runTest));
			ourMedians.push_back(
					runTests(10, repetitions, thresholds[i], false, size,
							runTest));
		}
	}

	if (mpiRank == 0) {
		int index = 0;

		for (int size : inputSizes) {
			unsigned long stdMedian = stdMedians[index / thresholds.size() / 2];

			for (int threshold : thresholds) {
				double speedUp = stdMedian / (double) ourMedians[index];
				double localEfficiency = speedUp / concurrentThreadsSupported;
				double globalEfficiency = speedUp / mpiSize;

				cout << "For threshold =         " << threshold << endl;
				cout << "  MPI size =            " << mpiSize << endl;
				cout << "  local size =          " << concurrentThreadsSupported
						<< endl;
				cout << "  input size =          " << size * mpiSize << endl;
				cout << "  repetitions =         " << repetitions << endl;
				cout << "  presort =             true" << endl;
				cout << "  median runtime =      " << ourMedians[index] << "us"
						<< endl;
				cout << "  speedUp =             " << speedUp << endl;
				cout << "  efficiency (local) =  " << localEfficiency << endl;
				cout << "  efficiency (global) = " << globalEfficiency << endl;

				index++;

				speedUp = stdMedian / (double) ourMedians[index];
				localEfficiency = speedUp / concurrentThreadsSupported;
				globalEfficiency = speedUp / mpiSize;

				cout << "For threshold =         " << threshold << endl;
				cout << "  MPI size =            " << mpiSize << endl;
				cout << "  local size =          " << concurrentThreadsSupported
						<< endl;
				cout << "  input size =          " << size * mpiSize << endl;
				cout << "  repetitions =         " << repetitions << endl;
				cout << "  presort =             false" << endl;
				cout << "  median runtime =      " << ourMedians[index] << "us"
						<< endl;
				cout << "  speedUp =             " << speedUp << endl;
				cout << "  efficiency (local) =  " << localEfficiency << endl;
				cout << "  efficiency (global) = " << globalEfficiency << endl;

				index++;
			}
		}
	}

	Finalize();
}
<commit_msg>Prepared some stuff for the big benchmark<commit_after>/*
 ============================================================================
 Name        : SampleSort
 Author      : Sebastian Schmidt, Lars Gottesbüren
 Version     :
 Copyright   : MIT License
 Description : Test the SampleSort algorithm smoothly and thoroughly.
 ============================================================================
 */

#include "mpi.h"
#include "SampleSort.h"
#include "Random.h"
#include "GatherSortSamplesStrategy.h"
#include "RecursiveSortSamplesStrategy.h"
#include "SortSamplesStrategy.h"
#include "SampleSortParams.h"
#include "SampleSizeStrategy.h"
#include "LogSampleSizeStrategy.h"
#include "RootSampleSizeStrategy.h"
#include "Debug.h"
#include "KWayMerge.h"

#include <math.h>
#include <iostream>
#include <cstdlib>
#include <vector>
#include <random>
#include <chrono>
#include <algorithm>
#include <thread>

using namespace std;
using namespace MPI;

const int TEST_DATA_SIZE = 50;

void generateRandomData(vector<int> &data, int minMax) {
	default_random_engine randomGenerator(getSeed());
	uniform_int_distribution<int> randomDistribution(-data.size() * minMax,
			data.size() * minMax);

	for (int i = 0; i < data.capacity(); i++) {
		data[i] = randomDistribution(randomGenerator);
		//cout << data[i] << endl;
	}
}

template<typename T>
bool checkSorted(vector<T> &array, int mpiRank, int mpiSize) {
	int size = array.size() * sizeof(T);
	vector<int> gatheredSizes;

	if (mpiRank == 0) {
		gatheredSizes.resize(mpiSize);
	}

	COMM_WORLD.Gather(&size, 1, MPI::INT, gatheredSizes.data(), 1, MPI::INT, 0);

	vector<T> allData;
	vector<int> offsets;

	if (mpiRank == 0) {
		offsets.resize(mpiSize);
		offsets[0] = 0;

		for (int i = 1; i < mpiSize; i++) {
			offsets[i] = gatheredSizes[i - 1] + offsets[i - 1];
		}

		allData.resize(
				(offsets[mpiSize - 1] + gatheredSizes[mpiSize - 1])
						/ sizeof(T));
	}

	COMM_WORLD.Gatherv(array.data(), array.size() * sizeof(T), MPI::BYTE,
			allData.data(), gatheredSizes.data(), offsets.data(), MPI::BYTE, 0);

	if (mpiRank == 0) {
		for (int i = 1; i < allData.size(); i++) {
			if (allData[i - 1] > allData[i]) {
				cout << "Sorting failed!" << endl;
				return false;
			}
		}

		//cout << "Sorting correct!" << endl;
		return true;
	}

	return true;
}

unsigned long runTest(int recursiveThreshold, bool withPresort, int inputSize) {
	int mpiSize = COMM_WORLD.Get_size();
	int mpiRank = COMM_WORLD.Get_rank();

	LogSampleSizeStrategy sss(6);
	//RootSampleSizeStrategy sss(2, 1);
	SampleSortParams params(mpiRank, mpiSize, 0, withPresort, -1, sss);
	// GatherSortSamplesStrategy sortSamplesStrategy;
	RecursiveSortSamplesStrategy<int> sortSamplesStrategy(recursiveThreshold);
	SampleSort<int> sorter(params, sortSamplesStrategy);
	vector<int> data(inputSize / mpiSize);
	generateRandomData(data, mpiSize);

	COMM_WORLD.Barrier();
	unsigned long start =
			chrono::high_resolution_clock::now().time_since_epoch().count();

	vector<int> result;
	sorter.sort(data, result, inputSize / mpiSize);

	unsigned long end =
			chrono::high_resolution_clock::now().time_since_epoch().count();
	COMM_WORLD.Barrier();

	unsigned long maxTime;
	unsigned long localTime = end - start;
	COMM_WORLD.Reduce(&localTime, &maxTime, 1, MPI::UNSIGNED_LONG, MPI::MAX, 0);

	double time = maxTime;
	time *= chrono::high_resolution_clock::period::type::num;
	time /= chrono::high_resolution_clock::period::type::den;

	if (!checkSorted(result, mpiRank, mpiSize)) {
		throw runtime_error("Result not sorted!");
	}

	if (mpiRank == 0) {
		//cout << "Sorting took " << (time * 1e6) << "us" << endl;
	}

	return time * 1e6;
}

unsigned long runStdSort(int recursiveThreshold, bool withPresort,
		int inputSize) {
	int mpiSize = COMM_WORLD.Get_size();
	int mpiRank = COMM_WORLD.Get_rank();

	if (mpiRank == 0) {
		vector<int> data(inputSize);
		generateRandomData(data, mpiSize);

		unsigned long start =
				chrono::high_resolution_clock::now().time_since_epoch().count();

		std::sort(data.begin(), data.end());

		unsigned long end =
				chrono::high_resolution_clock::now().time_since_epoch().count();

		unsigned long localTime = end - start;

		double time = localTime;
		time *= chrono::high_resolution_clock::period::type::num;
		time /= chrono::high_resolution_clock::period::type::den;

		if (mpiRank == 0) {
			//cout << "Sorting took " << (time * 1e6) << "us" << endl;
		}

		return time * 1e6;
	}

	return 0;
}

bool testAllEqualValue(int recursive_threshold, double value) {
	int mpiSize = COMM_WORLD.Get_size();
	int mpiRank = COMM_WORLD.Get_rank();

	vector<double> data(TEST_DATA_SIZE);
	for (vector<double>::iterator it = data.begin(); it != data.end(); it++) {
		*it = value;
	}

	LogSampleSizeStrategy sss(10);
	SampleSortParams params(mpiRank, mpiSize, 0, true, -1, sss);
	RecursiveSortSamplesStrategy<double> sortSamplesStrategy(
			recursive_threshold);
	SampleSort<double> sorter(params, sortSamplesStrategy);
	vector<double> results;
	sorter.sort(data, results, TEST_DATA_SIZE * mpiSize);
	return checkSorted(results, mpiRank, mpiSize);
}

unsigned long runTests(const int warmUp, const int runCount,
		int recursiveThreshold, bool withPresort, int inputSize,
		unsigned long test(int, bool, int)) {
	int mpiSize = COMM_WORLD.Get_size();
	int mpiRank = COMM_WORLD.Get_rank();
	vector<unsigned long> times;

	for (int i = 0; i < warmUp; i++) {
		if (mpiRank == 0 && (i % 50 == 0 || i == warmUp - 1)) {
			cout << "Warm up " << (i + 1) << "/" << warmUp << endl;
		}

		COMM_WORLD.Barrier();
		test(recursiveThreshold, withPresort, inputSize);
	}

	for (int i = 0; i < runCount; i++) {
		if (mpiRank == 0 && (i % 50 == 0 || i == runCount - 1)) {
			cout << "Running test no " << (i + 1) << "/" << runCount
					<< " with recursiveThreshold = " << recursiveThreshold
					<< " and with" << (withPresort ? "" : "out")
					<< " presort and with inputSize = " << inputSize << endl;
		}

		COMM_WORLD.Barrier();
		times.push_back(test(recursiveThreshold, withPresort, inputSize));
	}

	sort(times.begin(), times.end());
	unsigned long median = times[times.size() / 2];

	if (mpiRank == 0) {
		//cout << "Sorting time median = " << median << "us" << endl;
	}

	return median;
}

struct TestResult {
	int inputSize;
	bool withPresort;
	int threshold;
	unsigned long stdMedian;
	unsigned long ourMedian;
};

int main(int argc, char *argv[]) {
	Init(argc, argv);

	int mpiSize = COMM_WORLD.Get_size();
	int mpiRank = COMM_WORLD.Get_rank();

	//testAllEqualValue(50, 456.345634756);
	unsigned concurrentThreadsSupported = thread::hardware_concurrency();
	cout << mpiRank << ": concurrentThreadsSupported = "
			<< concurrentThreadsSupported << endl;

	vector<int> thresholds;
	vector<int> inputSizes;
	vector<TestResult> testResults;
	const int repetitions = 100;

	//thresholds.push_back(0);
	//thresholds.push_back(1);
	//thresholds.push_back(2);
	//thresholds.push_back(3);
	//thresholds.push_back(6);
	//thresholds.push_back(10);
	//thresholds.push_back(20);
	//thresholds.push_back(40);
	thresholds.push_back(80);
	//thresholds.push_back(160);
	//thresholds.push_back(320);
	thresholds.push_back(1 << 30);

	for (int i = 0; i < 23; i++) {
		inputSizes.push_back(1 << i);
	}

	COMM_WORLD.Barrier();

	for (int inputSize : inputSizes) {
		if (mpiRank == 0) {
			cout << " ====== TESTING STD::SORT  ====== " << endl;
		}

		struct TestResult testResult;
		testResult.inputSize = inputSize;
		testResult.stdMedian = runTests(10, repetitions, -1, false, inputSize,
				runStdSort);

		if (mpiRank == 0) {
			cout << " ====== TESTING SAMPLESORT ====== " << endl;
		}

		for (int i = 0; i < thresholds.size(); i++) {
			if (mpiRank == 0) {
				cout << " ====== ROUND " << (i + 1) << "/" << thresholds.size()
						<< " ====== " << endl;
			}

			testResult.threshold = thresholds[i];

			testResult.withPresort = true;
			testResult.ourMedian = runTests(10, repetitions, thresholds[i],
					true, inputSize, runTest);
			testResults.push_back(testResult);

			testResult.withPresort = false;
			testResult.ourMedian = runTests(10, repetitions, thresholds[i],
					false, inputSize, runTest);
			testResults.push_back(testResult);
		}
	}

	if (mpiRank == 0) {
		int index = 0;

		for (struct TestResult testResult : testResults) {
			double speedUp = testResult.stdMedian
					/ (double) testResult.ourMedian;
			double localEfficiency = speedUp / concurrentThreadsSupported;
			double globalEfficiency = speedUp / mpiSize;

			cout << "For threshold =         " << testResult.threshold << endl;
			cout << "  MPI size =            " << mpiSize << endl;
			cout << "  local size =          " << concurrentThreadsSupported
					<< endl;
			cout << "  input size =          " << testResult.inputSize << endl;
			cout << "  repetitions =         " << repetitions << endl;
			cout << "  presort =             " << testResult.withPresort
					<< endl;
			cout << "  median runtime =      " << testResult.ourMedian << "us"
					<< endl;
			cout << "  speedUp =             " << speedUp << endl;
			cout << "  efficiency (local) =  " << localEfficiency << endl;
			cout << "  efficiency (global) = " << globalEfficiency << endl;
		}

		cout << "<><><><><><><><><><><><><><><><><><><><>" << endl;
		cout << "<><><><><><> PGFPLOT OUTPUT <><><><><><>" << endl;
		cout << "<><><><><><><><><><><><><><><><><><><><>" << endl;

		cout << " ==== STD::SORT  ====" << endl;
		cout << "Runtime:" << endl;
		for (int i = 0; i < testResults.size(); i += thresholds.size() * 2) {
			cout << "(" << testResults[i].inputSize << ", "
					<< testResults[i].stdMedian << ") ";
		}
		cout << endl;

		cout << " ==== SAMPLESORT ====" << endl;
		for (int i = 0; i < thresholds.size() * 2; i++) {
			cout << "Runtime (threshold = " << testResults[i].threshold
					<< ", withPresort = " << testResults[i].withPresort << "):"
					<< endl;

			for (int j = i; j < testResults.size();
					j += thresholds.size() * 2) {
				cout << "(" << testResults[j].inputSize << ", "
						<< testResults[j].ourMedian << ") ";
			}
			cout << endl;
		}

		for (int i = 0; i < thresholds.size() * 2; i++) {
			cout << "Speedup (threshold = " << testResults[i].threshold
					<< ", withPresort = " << testResults[i].withPresort << "):"
					<< endl;

			for (int j = i; j < testResults.size();
					j += thresholds.size() * 2) {
				cout << "(" << testResults[j].inputSize << ", "
						<< (testResults[j].stdMedian
								/ (double) testResults[j].ourMedian) << ") ";
			}
			cout << endl;
		}
	}

	Finalize();
}
<|endoftext|>