<commit_before>#include <string>
#include <iostream>
#include <ctime>
#include <array>
#include <cmath>

#include "solver.h"
#include "message.h"
#include "key.h"
#include "language_data.h"

Solver::Solver(Message* message, Key &key) : message_(message), key_(key), bestKey_(nullptr),
											tempTabu_(std::unordered_set<std::string>()),
											optimalTabu_((std::unordered_set<std::string>()))
{
	srand(time(nullptr));
}

void Solver::SetKey(Key &key)
{
	key_ = key;
}

void Solver::Start()
{
	int lastScore = CalculateScore(message_->DecryptInt(key_));
	int bestScore = lastScore;
	int currentBestScore = bestScore;
	unsigned int iterations = 0;
	const int maxTolerance = 40;
	const int endIterationShuffles = 5;
	const int tempClearProbability = 80;

	int tolerance = 0;
	int currentTolerance = 0;
	bool improved = false;
	int currentTabu = 0;

	Key* bestKey = new Key(key_);
	Key* currentBestKey = new Key(key_);

	currentBestScore = bestScore = lastScore = CalculateScore(message_->DecryptInt(key_));

	while (bestScore < 42000 && iterations < 80)
	{
		improved = false;
		for (int p1 = 0; p1 < key_.GetLength(); p1++)
		{
			for (int p2 = 0; p2 < key_.GetLength(); p2++)
			{
				if (!key_.Swap(p1, p2)) continue;
				int score = CalculateScore(message_->DecryptInt(key_));

				if (tempTabu_.find(key_.AsPlainText()) != std::end(tempTabu_) ||
					optimalTabu_.find(key_.AsPlainText()) != std::end(optimalTabu_))
				{
					//std::cout << "Blacklisted " << std::endl;
					score = -10000;
				}
				else
				{
					score = CalculateScore(message_->DecryptInt(key_));
				}
				tempTabu_.insert(key_.AsPlainText());

				if (maxTolerance)
				{
					tolerance = rand() % (maxTolerance - currentTolerance + 1);
				}

				if (score < lastScore - tolerance)
				{
					key_.Swap(p1, p2); //undo last swap
				}
				else
				{
					lastScore = score;
					if (lastScore > bestScore)
					{
						improved = true;
						bestScore = lastScore;
						delete bestKey;
						bestKey = new Key(key_);
						//delete currentBestKey;
						//currentBestKey = new Key(*key_);
					}

					if (score > currentBestScore)
					{
						currentBestScore = score;
						delete currentBestKey;
						currentBestKey = new Key(key_);
					}
				}
			}
		}

		if (!improved)
		{
			if (++currentTolerance >= maxTolerance)
			{
				currentTolerance = 0;
			}

			currentTabu++;
			if (currentTabu >= 300 /* max tabu */)
			{
				std::cout << "The plateau's clean, no dirt to be seen" << std::endl;
				optimalTabu_.insert(currentBestKey->AsPlainText());
				currentBestScore = -10000;

				if (rand() % 2)
				{
					std::cout << "Restart w/ random key" << std::endl;
					key_.RandomShuffle(100);
				}
				else
				{
					std::cout << "Back to best key" << std::endl;
					key_ = *bestKey;
				}
				currentTabu = 0;
			}
		}
		else
		{
			currentTolerance = 0;
			currentTabu = 0;
		}
		key_.RandomShuffle(endIterationShuffles);
		if (tempTabu_.find(key_.AsPlainText()) != std::end(tempTabu_) ||
			optimalTabu_.find(key_.AsPlainText()) != std::end(optimalTabu_))
		{
			lastScore = -10000;
		}
		else
		{
			/*key_->SetMapSymbol('9', 8);
			key_->SetMapSymbol('%', 11);
			key_->SetMapSymbol('P', 8);
			key_->SetMapSymbol('/', 10);
			key_->SetMapSymbol('Z', 4);
			key_->SetMapSymbol('U', 8);
			key_->SetMapSymbol('B', 11);
			key_->SetMapSymbol('k', 8);
			key_->SetMapSymbol('O', 13);*/
			lastScore = CalculateScore(message_->DecryptInt(key_));
		}

		if ((rand() % 100) < tempClearProbability) { //CLEAR_TABU_PROB
			std::cout << "Clearing temp" << std::endl;
			tempTabu_.clear();
		}

		tolerance = 0;
		iterations++;
		std::cout << "Iteration " << iterations - 1 << " done with score " << currentBestScore << ", best is " << bestScore << std::endl;
	} //end of hill climber loop
	bestKey_ = bestKey;

	std::cout << iterations << " iterations completed" << std::endl;
	std::cout << "Best key is " << bestKey->AsPlainText() << std::endl;
	std::cout << "Best score is " << bestScore << std::endl;
	std::cout << "And it decrypts to" << std::endl;
	std::cout << message_->DecryptAsString(*bestKey_);

}

int Solver::CalculateScore(const std::vector<int>& plaintext)
{
	unsigned int score = 0;

	unsigned int biscore, triscore, tetrascore, pentascore;
	biscore = triscore = tetrascore = pentascore = 0;

	auto it = std::begin(plaintext);

	//for (unsigned int i = 0; i < len - 1; i++)
	size_t remaining = plaintext.size();
	while (it != std::end(plaintext))
	{
		int gram = *(it++); //1st
		auto it2 = it;
		if (remaining > 1 || it2 != std::end(plaintext)) {
			gram *= 26;
			gram += *(it2++);
		}

		biscore += LanguageData::GetBigramFrequency(gram);

		if (remaining > 2 || it2 != std::end(plaintext)) {
			gram *= 26;
			gram += *(it2++);
			triscore += LanguageData::GetTri(gram);
		}

		if (remaining > 3 || it2 != std::end(plaintext)) {
			gram *= 26;
			gram += *(it2++);
			tetrascore += LanguageData::GetTetra(gram);
		}

		if (remaining > 4 || it2 != std::end(plaintext)) {
			gram *= 26;
			gram += *(it2++);
			pentascore += LanguageData::GetPenta(gram); //hehe, pentagram
		}
		remaining--;
	}
	//std::cout << "Scored " << pentascore << " " << (tetrascore >> 1) << " " << (triscore >> 2 ) << " " << (biscore >> 3) << std::endl;
	score = pentascore + (tetrascore >> 1) + (triscore >> 2) + (biscore >> 3);
	//score = pentascore + (tetrascore) + (triscore) + (biscore);

	//update statistics

//This is a perfectly normal way to value-initialize an array in C++11
//GCC is sadly being too paranoid about this
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
	std::array<int, 26> freqs {};
#pragma GCC diagnostic pop
	int unique = 0;
	for (size_t i = 0; i < plaintext.size(); i++)
	{
		int idx = plaintext[i];
		if (!freqs[idx])
		{
			unique++;
		}
		freqs[idx]++;
	}
	double probMass = (double)plaintext.size() / unique;
	double entropy = 0.0;
	double entropyProb = 0.0;
	double ioc = 0.0;
	double chi2 = 0.0;
	double chiTemp = 0.0;
	for (int i = 0; i < 26; i++)
	{
		if (freqs[i] > 1)
		{
			ioc += freqs[i] * (freqs[i] - 1);
		}

		if (freqs[i])
		{
			entropyProb = (double)freqs[i] / plaintext.size();
			entropy += entropyProb * (std::log(entropyProb) / std::log(2));

			chiTemp = freqs[i] - probMass;
			chiTemp *= chiTemp;
			chiTemp /= probMass;
			chi2 += chiTemp;
		}
	}

	ioc /= plaintext.size() * (plaintext.size() - 1);
	chi2 /= plaintext.size();
	entropy *= -1;

	double dioc = 0.0; //GetDIoC(plaintext);

	double multiplier = 1.0;
	multiplier *= 1.05 - (5 * std::abs(ioc - LanguageData::EnglishIoC));
	//multiplier *= 1.05 - ((5 >> 1) * std::abs(dioc - LanguageData::EnglishDIoC));
	multiplier *= 1.05 - (5 * std::abs(chi2 - LanguageData::EnglishChi2)) / 60.0;
	multiplier *= 1.05 - (5 * std::abs(entropy - LanguageData::EnglishEntropy)) / 150.0;

	return int(score * multiplier);
}

double Solver::GetDIoC(std::vector<int>& plaintext)
{
	#pragma GCC diagnostic push
	#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
	std::array<int, 676> freqs {};
	#pragma GCC diagnostic pop

	double dioc = 0;
	int count = 0;

	for (size_t i = 0; i < plaintext.size() - 1; i += 2)
	{
		int idx1 = plaintext[i];
		int idx2 = plaintext[i + 1];
		freqs[idx1 * 26 + idx2]++;
		count++;
	}
	for (size_t i = 0; i < freqs.size(); i++)
	{
		if(freqs[i] > 1)
		{
			dioc += freqs[i] * (freqs[i] - 1);
		}
	}

	dioc /= count * (count - 1);
	std::cout << "DIOC count is " << count << std::endl;
	return dioc;
}

void Solver::TestScore(std::string& plaintext)
{
	//shut up
	//std::cout << "Got " << CalculateScore(plaintext) << std::endl;
}
<commit_msg>Turning keys within the solver into references<commit_after>#include <string>
#include <iostream>
#include <ctime>
#include <array>
#include <cmath>

#include "solver.h"
#include "message.h"
#include "key.h"
#include "language_data.h"

Solver::Solver(Message* message, Key &key) : message_(message), key_(key), bestKey_(nullptr),
											tempTabu_(std::unordered_set<std::string>()),
											optimalTabu_((std::unordered_set<std::string>()))
{
	srand(time(nullptr));
}

void Solver::SetKey(Key &key)
{
	key_ = key;
}

void Solver::Start()
{
	int lastScore = CalculateScore(message_->DecryptInt(key_));
	int bestScore = lastScore;
	int currentBestScore = bestScore;
	unsigned int iterations = 0;
	const int maxTolerance = 40;
	const int endIterationShuffles = 5;
	const int tempClearProbability = 80;

	int tolerance = 0;
	int currentTolerance = 0;
	bool improved = false;
	int currentTabu = 0;

	Key bestKey(key_);
	Key currentBestKey(key_);

	currentBestScore = bestScore = lastScore = CalculateScore(message_->DecryptInt(key_));

	while (bestScore < 42000 && iterations < 80)
	{
		improved = false;
		for (int p1 = 0; p1 < key_.GetLength(); p1++)
		{
			for (int p2 = 0; p2 < key_.GetLength(); p2++)
			{
				if (!key_.Swap(p1, p2)) continue;
				int score = CalculateScore(message_->DecryptInt(key_));

				if (tempTabu_.find(key_.AsPlainText()) != std::end(tempTabu_) ||
					optimalTabu_.find(key_.AsPlainText()) != std::end(optimalTabu_))
				{
					//std::cout << "Blacklisted " << std::endl;
					score = -10000;
				}
				else
				{
					score = CalculateScore(message_->DecryptInt(key_));
				}
				tempTabu_.insert(key_.AsPlainText());

				if (maxTolerance)
				{
					tolerance = rand() % (maxTolerance - currentTolerance + 1);
				}

				if (score < lastScore - tolerance)
				{
					key_.Swap(p1, p2); //undo last swap
				}
				else
				{
					lastScore = score;
					if (lastScore > bestScore)
					{
						improved = true;
						bestScore = lastScore;
						bestKey = key_;
					}

					if (score > currentBestScore)
					{
						currentBestScore = score;
						currentBestKey = key_;
					}
				}
			}
		}

		if (!improved)
		{
			if (++currentTolerance >= maxTolerance)
			{
				currentTolerance = 0;
			}

			currentTabu++;
			if (currentTabu >= 300 /* max tabu */)
			{
				std::cout << "The plateau's clean, no dirt to be seen" << std::endl;
				optimalTabu_.insert(currentBestKey.AsPlainText());
				currentBestScore = -10000;

				if (rand() % 2)
				{
					std::cout << "Restart w/ random key" << std::endl;
					key_.RandomShuffle(100);
				}
				else
				{
					std::cout << "Back to best key" << std::endl;
					key_ = bestKey;
				}
				currentTabu = 0;
			}
		}
		else
		{
			currentTolerance = 0;
			currentTabu = 0;
		}
		key_.RandomShuffle(endIterationShuffles);
		if (tempTabu_.find(key_.AsPlainText()) != std::end(tempTabu_) ||
			optimalTabu_.find(key_.AsPlainText()) != std::end(optimalTabu_))
		{
			lastScore = -10000;
		}
		else
		{
			/*key_->SetMapSymbol('9', 8);
			key_->SetMapSymbol('%', 11);
			key_->SetMapSymbol('P', 8);
			key_->SetMapSymbol('/', 10);
			key_->SetMapSymbol('Z', 4);
			key_->SetMapSymbol('U', 8);
			key_->SetMapSymbol('B', 11);
			key_->SetMapSymbol('k', 8);
			key_->SetMapSymbol('O', 13);*/
			lastScore = CalculateScore(message_->DecryptInt(key_));
		}

		if ((rand() % 100) < tempClearProbability) { //CLEAR_TABU_PROB
			std::cout << "Clearing temp" << std::endl;
			tempTabu_.clear();
		}

		tolerance = 0;
		iterations++;
		std::cout << "Iteration " << iterations - 1 << " done with score " << currentBestScore << ", best is " << bestScore << std::endl;
	} //end of hill climber loop

	std::cout << iterations << " iterations completed" << std::endl;
	std::cout << "Best key is " << bestKey.AsPlainText() << std::endl;
	std::cout << "Best score is " << bestScore << std::endl;
	std::cout << "And it decrypts to" << std::endl;
	std::cout << message_->DecryptAsString(bestKey);

}

int Solver::CalculateScore(const std::vector<int>& plaintext)
{
	unsigned int score = 0;

	unsigned int biscore, triscore, tetrascore, pentascore;
	biscore = triscore = tetrascore = pentascore = 0;

	auto it = std::begin(plaintext);

	//for (unsigned int i = 0; i < len - 1; i++)
	size_t remaining = plaintext.size();
	while (it != std::end(plaintext))
	{
		int gram = *(it++); //1st
		auto it2 = it;
		if (remaining > 1 || it2 != std::end(plaintext)) {
			gram *= 26;
			gram += *(it2++);
		}

		biscore += LanguageData::GetBigramFrequency(gram);

		if (remaining > 2 || it2 != std::end(plaintext)) {
			gram *= 26;
			gram += *(it2++);
			triscore += LanguageData::GetTri(gram);
		}

		if (remaining > 3 || it2 != std::end(plaintext)) {
			gram *= 26;
			gram += *(it2++);
			tetrascore += LanguageData::GetTetra(gram);
		}

		if (remaining > 4 || it2 != std::end(plaintext)) {
			gram *= 26;
			gram += *(it2++);
			pentascore += LanguageData::GetPenta(gram); //hehe, pentagram
		}
		remaining--;
	}
	//std::cout << "Scored " << pentascore << " " << (tetrascore >> 1) << " " << (triscore >> 2 ) << " " << (biscore >> 3) << std::endl;
	score = pentascore + (tetrascore >> 1) + (triscore >> 2) + (biscore >> 3);
	//score = pentascore + (tetrascore) + (triscore) + (biscore);

	//update statistics

//This is a perfectly normal way to value-initialize an array in C++11
//GCC is sadly being too paranoid about this
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
	std::array<int, 26> freqs {};
#pragma GCC diagnostic pop
	int unique = 0;
	for (size_t i = 0; i < plaintext.size(); i++)
	{
		int idx = plaintext[i];
		if (!freqs[idx])
		{
			unique++;
		}
		freqs[idx]++;
	}
	double probMass = (double)plaintext.size() / unique;
	double entropy = 0.0;
	double entropyProb = 0.0;
	double ioc = 0.0;
	double chi2 = 0.0;
	double chiTemp = 0.0;
	for (int i = 0; i < 26; i++)
	{
		if (freqs[i] > 1)
		{
			ioc += freqs[i] * (freqs[i] - 1);
		}

		if (freqs[i])
		{
			entropyProb = (double)freqs[i] / plaintext.size();
			entropy += entropyProb * (std::log(entropyProb) / std::log(2));

			chiTemp = freqs[i] - probMass;
			chiTemp *= chiTemp;
			chiTemp /= probMass;
			chi2 += chiTemp;
		}
	}

	ioc /= plaintext.size() * (plaintext.size() - 1);
	chi2 /= plaintext.size();
	entropy *= -1;

	double dioc = 0.0; //GetDIoC(plaintext);

	double multiplier = 1.0;
	multiplier *= 1.05 - (5 * std::abs(ioc - LanguageData::EnglishIoC));
	//multiplier *= 1.05 - ((5 >> 1) * std::abs(dioc - LanguageData::EnglishDIoC));
	multiplier *= 1.05 - (5 * std::abs(chi2 - LanguageData::EnglishChi2)) / 60.0;
	multiplier *= 1.05 - (5 * std::abs(entropy - LanguageData::EnglishEntropy)) / 150.0;

	return int(score * multiplier);
}

double Solver::GetDIoC(std::vector<int>& plaintext)
{
	#pragma GCC diagnostic push
	#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
	std::array<int, 676> freqs {};
	#pragma GCC diagnostic pop

	double dioc = 0;
	int count = 0;

	for (size_t i = 0; i < plaintext.size() - 1; i += 2)
	{
		int idx1 = plaintext[i];
		int idx2 = plaintext[i + 1];
		freqs[idx1 * 26 + idx2]++;
		count++;
	}
	for (size_t i = 0; i < freqs.size(); i++)
	{
		if(freqs[i] > 1)
		{
			dioc += freqs[i] * (freqs[i] - 1);
		}
	}

	dioc /= count * (count - 1);
	std::cout << "DIOC count is " << count << std::endl;
	return dioc;
}

void Solver::TestScore(std::string& plaintext)
{
	//shut up
	//std::cout << "Got " << CalculateScore(plaintext) << std::endl;
}
<|endoftext|>


<commit_before>#include "sphere.h"
#include "utils.h"

namespace batoid {
    Sphere::Sphere(double R) : _R(R), _Rsq(R*R), _Rinv(1./R), _Rinvsq(1./R/R) {}

    double Sphere::sag(double x, double y) const {
        if (_R != 0)
            return _R*(1-std::sqrt(1-(x*x + y*y)*_Rinvsq));
        return 0.0;
    }

    Vector3d Sphere::normal(double x, double y) const {
        if (_R == 0.0)
            return Vector3d(0,0,1);
        double r = std::sqrt(x*x + y*y);
        if (r == 0)
            return Vector3d(0,0,1);
        double dzdr1 = dzdr(r);
        return Vector3d(-dzdr1*x/r, -dzdr1*y/r, 1).normalized();
    }

    bool Sphere::timeToIntersect(const Ray& r, double& t) const {
        double vr2 = r.v[0]*r.v[0] + r.v[1]*r.v[1];
        double vz2 = r.v[2]*r.v[2];
        double vrr0 = r.v[0]*r.r[0] + r.v[1]*r.r[1];
        double r02 = r.r[0]*r.r[0] + r.r[1]*r.r[1];
        double z0term = (r.r[2]-_R);

        // Quadratic equation coefficients
        double a = vz2 + vr2;
        double b = 2*r.v[2]*z0term + 2*vrr0;
        double c = z0term*z0term - _Rsq + r02;

        double r1, r2;
        int n = solveQuadratic(a, b, c, r1, r2);

        // Should probably check the solutions here since we obtained the quadratic
        // formula above by squaring both sides of an equation.
        if (n == 0) {
            return false;
        } else if (n == 1) {
            if (r1 < 0)
                return false;
            t = r1;
        } else {
            if (r1 < 0) {
                if (r2 < 0)
                    return false;
                else
                    t = r2;
            } else
                t = std::min(r1, r2);
        }
        t += r.t;
        return true;
    }

    double Sphere::dzdr(double r) const {
        double rat = r*_Rinv;
        return rat/std::sqrt(1-rat*rat);
    }

}
<commit_msg>Choose correct time for Sphere intersect<commit_after>#include "sphere.h"
#include "utils.h"

namespace batoid {
    Sphere::Sphere(double R) : _R(R), _Rsq(R*R), _Rinv(1./R), _Rinvsq(1./R/R) {}

    double Sphere::sag(double x, double y) const {
        if (_R != 0)
            return _R*(1-std::sqrt(1-(x*x + y*y)*_Rinvsq));
        return 0.0;
    }

    Vector3d Sphere::normal(double x, double y) const {
        if (_R == 0.0)
            return Vector3d(0,0,1);
        double r = std::sqrt(x*x + y*y);
        if (r == 0)
            return Vector3d(0,0,1);
        double dzdr1 = dzdr(r);
        return Vector3d(-dzdr1*x/r, -dzdr1*y/r, 1).normalized();
    }

    bool Sphere::timeToIntersect(const Ray& r, double& t) const {
        double vr2 = r.v[0]*r.v[0] + r.v[1]*r.v[1];
        double vz2 = r.v[2]*r.v[2];
        double vrr0 = r.v[0]*r.r[0] + r.v[1]*r.r[1];
        double r02 = r.r[0]*r.r[0] + r.r[1]*r.r[1];
        double z0term = (r.r[2]-_R);

        // Quadratic equation coefficients
        double a = vz2 + vr2;
        double b = 2*r.v[2]*z0term + 2*vrr0;
        double c = z0term*z0term - _Rsq + r02;

        double t1, t2;
        int n = solveQuadratic(a, b, c, t1, t2);

        // Should probably check the solutions here since we obtained the quadratic
        // formula above by squaring both sides of an equation.
        if (n == 0) {
            return false;
        } else if (n == 1) {
            if (t1 < 0)
                return false;
            t = t1;
        } else {
            if (t1 < 0) {
                if (t2 < 0)
                    return false;
                else
                    t = t2;
            } else {
                // We need to pick whichever time is most consistent with the sag.
                Ray r1 = r.propagatedToTime(r.t + t1);
                Ray r2 = r.propagatedToTime(r.t + t2);
                double d1 = std::abs(sag(r1.r[0], r1.r[1]) - r1.r[2]);
                double d2 = std::abs(sag(r2.r[0], r2.r[1]) - r2.r[2]);
                t = (d1 < d2) ? t1 : t2;
            }
        }
        t += r.t;
        return true;
    }

    double Sphere::dzdr(double r) const {
        double rat = r*_Rinv;
        return rat/std::sqrt(1-rat*rat);
    }

}
<|endoftext|>


<commit_before>/*!
 * FrameReceiverRxThreadUnitTest.cpp
 *
 *  Created on: Feb 5, 2015
 *      Author: Tim Nicholls, STFC Application Engineering Group
 */

#include <boost/test/unit_test.hpp>

#include "FrameReceiverUDPRxThread.h"
#include "IpcMessage.h"
#include "SharedBufferManager.h"
#include <log4cxx/logger.h>
#include <log4cxx/consoleappender.h>
#include <log4cxx/basicconfigurator.h>
#include <log4cxx/simplelayout.h>
#include "../include/DummyUDPFrameDecoder.h"

namespace FrameReceiver
{
class FrameReceiverRxThreadTestProxy
{
public:
  FrameReceiverRxThreadTestProxy(FrameReceiver::FrameReceiverConfig& config) :
      config_(config)
  {
    // Override default RX buffer size on OS X as Linux default
    // is too large for test to pass
#ifdef __MACH__
    config_.rx_recv_buffer_size_ = 1048576;
#endif
  }

  std::string& get_rx_channel_endpoint(void)
  {
    return config_.rx_channel_endpoint_;
  }
private:
  FrameReceiver::FrameReceiverConfig& config_;
};
}
class FrameReceiverRxThreadTestFixture
{
public:
  FrameReceiverRxThreadTestFixture() :
      rx_channel(ZMQ_PAIR),
      logger(log4cxx::Logger::getLogger("FrameReceiverRxThreadUnitTest")),
      proxy(config),
      frame_decoder(new FrameReceiver::DummyUDPFrameDecoder()),
      buffer_manager(new OdinData::SharedBufferManager("TestSharedBuffer", 10000, 1000))
  {

    BOOST_TEST_MESSAGE("Setup test fixture");

    // Create a log4cxx console appender so that thread messages can be printed, suppress debug messages
    log4cxx::ConsoleAppender* consoleAppender = new log4cxx::ConsoleAppender(log4cxx::LayoutPtr(new log4cxx::SimpleLayout()));
    log4cxx::helpers::Pool p;
    consoleAppender->activateOptions(p);
    log4cxx::BasicConfigurator::configure(log4cxx::AppenderPtr(consoleAppender));
    log4cxx::Logger::getRootLogger()->setLevel(log4cxx::Level::getInfo());

    frame_decoder->init(logger);

    // Bind the endpoint of the channel to communicate with the RX thread
    rx_channel.bind(proxy.get_rx_channel_endpoint());

  }

  ~FrameReceiverRxThreadTestFixture()
  {
    BOOST_TEST_MESSAGE("Tear down test fixture");
  }

  OdinData::IpcChannel rx_channel;
  FrameReceiver::FrameReceiverConfig config;
  log4cxx::LoggerPtr logger;
  FrameReceiver::FrameReceiverRxThreadTestProxy proxy;
  FrameReceiver::FrameDecoderPtr frame_decoder;
  OdinData::SharedBufferManagerPtr buffer_manager;
};

BOOST_FIXTURE_TEST_SUITE(FrameReceiverRxThreadUnitTest, FrameReceiverRxThreadTestFixture);

BOOST_AUTO_TEST_CASE( CreateAndPingRxThread )
{

  bool initOK = true;

  try {
    FrameReceiver::FrameReceiverUDPRxThread rxThread(config, buffer_manager, frame_decoder, 1);
    rxThread.start();
    OdinData::IpcMessage::MsgType msg_type = OdinData::IpcMessage::MsgTypeCmd;
    OdinData::IpcMessage::MsgVal  msg_val =  OdinData::IpcMessage::MsgValCmdStatus;

    int loopCount = 500;
    int replyCount = 0;
    int timeoutCount = 0;
    bool msgMatch = true;

    for (int loop = 0; loop < loopCount; loop++)
    {
      OdinData::IpcMessage message(msg_type, msg_val);
      message.set_param<int>("count", loop);
      rx_channel.send(message.encode());
    }

    while ((replyCount < loopCount) && (timeoutCount < 10))
    {
      if (rx_channel.poll(100))
      {
        std::string reply = rx_channel.recv();

        OdinData::IpcMessage response(reply.c_str());
        msgMatch &= (response.get_msg_type() == OdinData::IpcMessage::MsgTypeAck);
        msgMatch &= (response.get_msg_val() == OdinData::IpcMessage::MsgValCmdStatus);
        msgMatch &= (response.get_param<int>("count", -1) == replyCount);
        replyCount++;
        timeoutCount = 0;
      }
      else
      {
        timeoutCount++;
      }
    }
    rxThread.stop();
    BOOST_CHECK_EQUAL(msgMatch, true);
    BOOST_CHECK_EQUAL(loopCount, replyCount);
    BOOST_CHECK_EQUAL(timeoutCount, 0);
  }
  catch (OdinData::OdinDataException& e)
  {
    initOK = false;
    BOOST_TEST_MESSAGE("Creation of FrameReceiverRxThread failed: " << e.what());
  }
  BOOST_REQUIRE_EQUAL(initOK, true);

}

BOOST_AUTO_TEST_SUITE_END();
<commit_msg>Make RX thread unit test understand buffer precharge request.<commit_after>/*!
 * FrameReceiverRxThreadUnitTest.cpp
 *
 *  Created on: Feb 5, 2015
 *      Author: Tim Nicholls, STFC Application Engineering Group
 */

#include <boost/test/unit_test.hpp>

#include "FrameReceiverUDPRxThread.h"
#include "IpcMessage.h"
#include "SharedBufferManager.h"
#include <log4cxx/logger.h>
#include <log4cxx/consoleappender.h>
#include <log4cxx/basicconfigurator.h>
#include <log4cxx/simplelayout.h>
#include "../include/DummyUDPFrameDecoder.h"

namespace FrameReceiver
{
class FrameReceiverRxThreadTestProxy
{
public:
  FrameReceiverRxThreadTestProxy(FrameReceiver::FrameReceiverConfig& config) :
      config_(config)
  {
    // Override default RX buffer size on OS X as Linux default
    // is too large for test to pass
#ifdef __MACH__
    config_.rx_recv_buffer_size_ = 1048576;
#endif
  }

  std::string& get_rx_channel_endpoint(void)
  {
    return config_.rx_channel_endpoint_;
  }
private:
  FrameReceiver::FrameReceiverConfig& config_;
};
}
class FrameReceiverRxThreadTestFixture
{
public:
  FrameReceiverRxThreadTestFixture() :
      rx_channel(ZMQ_PAIR),
      logger(log4cxx::Logger::getLogger("FrameReceiverRxThreadUnitTest")),
      proxy(config),
      frame_decoder(new FrameReceiver::DummyUDPFrameDecoder()),
      buffer_manager(new OdinData::SharedBufferManager("TestSharedBuffer", 10000, 1000))
  {

    BOOST_TEST_MESSAGE("Setup test fixture");

    // Create a log4cxx console appender so that thread messages can be printed, suppress debug messages
    log4cxx::ConsoleAppender* consoleAppender = new log4cxx::ConsoleAppender(log4cxx::LayoutPtr(new log4cxx::SimpleLayout()));
    log4cxx::helpers::Pool p;
    consoleAppender->activateOptions(p);
    log4cxx::BasicConfigurator::configure(log4cxx::AppenderPtr(consoleAppender));
    log4cxx::Logger::getRootLogger()->setLevel(log4cxx::Level::getInfo());

    frame_decoder->init(logger);

    // Bind the endpoint of the channel to communicate with the RX thread
    rx_channel.bind(proxy.get_rx_channel_endpoint());

  }

  ~FrameReceiverRxThreadTestFixture()
  {
    BOOST_TEST_MESSAGE("Tear down test fixture");
  }

  OdinData::IpcChannel rx_channel;
  FrameReceiver::FrameReceiverConfig config;
  log4cxx::LoggerPtr logger;
  FrameReceiver::FrameReceiverRxThreadTestProxy proxy;
  FrameReceiver::FrameDecoderPtr frame_decoder;
  OdinData::SharedBufferManagerPtr buffer_manager;
};

BOOST_FIXTURE_TEST_SUITE(FrameReceiverRxThreadUnitTest, FrameReceiverRxThreadTestFixture);

BOOST_AUTO_TEST_CASE( CreateAndPingRxThread )
{

  bool initOK = true;

  try {
    FrameReceiver::FrameReceiverUDPRxThread rxThread(config, buffer_manager, frame_decoder, 1);
    rxThread.start();

    // The RX thread will, immediately on startup, send a buffer precharge request, so check
    // this is received with the correct parameters

    std::string precharge_request = rx_channel.recv();
    OdinData::IpcMessage precharge_msg(precharge_request.c_str());
    BOOST_CHECK_EQUAL(precharge_msg.get_msg_type(), OdinData::IpcMessage::MsgTypeCmd);
    BOOST_CHECK_EQUAL(precharge_msg.get_msg_val(), OdinData::IpcMessage::MsgValCmdBufferPrechargeRequest);

    OdinData::IpcMessage::MsgType msg_type = OdinData::IpcMessage::MsgTypeCmd;
    OdinData::IpcMessage::MsgVal  msg_val =  OdinData::IpcMessage::MsgValCmdStatus;

    int loopCount = 1;
    int replyCount = 0;
    int timeoutCount = 0;
    bool msgMatch = true;

    for (int loop = 0; loop < loopCount; loop++)
    {
      OdinData::IpcMessage message(msg_type, msg_val);
      message.set_param<int>("count", loop);
      rx_channel.send(message.encode());
    }

    while ((replyCount < loopCount) && (timeoutCount < 10))
    {
      if (rx_channel.poll(100))
      {
        std::string reply = rx_channel.recv();

        OdinData::IpcMessage response(reply.c_str());
        msgMatch &= (response.get_msg_type() == OdinData::IpcMessage::MsgTypeAck);
        msgMatch &= (response.get_msg_val() == OdinData::IpcMessage::MsgValCmdStatus);
        msgMatch &= (response.get_param<int>("count", -1) == replyCount);
        replyCount++;
        timeoutCount = 0;
      }
      else
      {
        timeoutCount++;
      }
    }
    rxThread.stop();
    BOOST_CHECK_EQUAL(msgMatch, true);
    BOOST_CHECK_EQUAL(loopCount, replyCount);
    BOOST_CHECK_EQUAL(timeoutCount, 0);
  }
  catch (OdinData::OdinDataException& e)
  {
    initOK = false;
    BOOST_TEST_MESSAGE("Creation of FrameReceiverRxThread failed: " << e.what());
  }
  BOOST_REQUIRE_EQUAL(initOK, true);

}

BOOST_AUTO_TEST_SUITE_END();
<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
/// \file  string.cpp
//------------------------------------------------------------------------------
/// \brief Implementation of general purpose functions for string processing
//------------------------------------------------------------------------------
// Copyright (c) 2010 Serge Aleynikov <saleyn@gmail.com>
// Created: 2010-05-06
//------------------------------------------------------------------------------
/*
***** BEGIN LICENSE BLOCK *****

This file is part of the utxx open-source project.

Copyright (C) 2010 Serge Aleynikov <saleyn@gmail.com>

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

***** END LICENSE BLOCK *****
*/

#include <utxx/string.hpp>
#include <utxx/print_opts.hpp>

namespace utxx {

std::string to_bin_string(const char* a_buf, size_t a_sz,
                          bool a_hex, bool a_readable, bool a_eol)
{
    std::stringstream out;
    const char* begin = a_buf, *end = a_buf + a_sz;
    print_opts  opts  = a_hex
                      ? (a_readable ? print_opts::printable_or_hex : print_opts::hex)
                      : (a_readable ? print_opts::printable_or_dec : print_opts::dec);
    output(out, begin, end, opts, ",", "", "\"", "<<", ">>");
    if (a_eol) out << std::endl;
    return out.str();
}

bool wildcard_match(const char* a_input, const char* a_pattern)
{
    // Pattern match a_input against a_pattern, and exit
    // at the end of the input string
    for(const char* ip = nullptr, *pp = nullptr; *a_input;)
        if (*a_pattern == '*') {
            if (!*++a_pattern)
                return true;    // Reached '*' at the end of pattern
            pp = a_pattern;     // Store matching state right after '*'
            ip = a_input;
        } else if ((*a_pattern == *a_input) || (*a_pattern == '?')) {
            a_pattern++;        // Continue successful input match
            a_input++;
        } else if (pp) {
            a_pattern = pp;     // Match failed - restore state of pattern after '*'
            a_input   = ++ip;   // Advance the input on every match failure
        } else
            return false;       // Match failed before the first '*' is found

    // Skip trailing '*' in the pattern, since they don't affect the outcome:
    while (*a_pattern == '*') a_pattern++;

    // This point is reached only when the a_input string was fully
    // exhaused. If at this point the a_pattern is exhaused too ('\0'),
    // there's a match, otherwise pattern match is incomplete.
    return !*a_pattern;
}

} // namespace utxx
<commit_msg>Update string.cpp<commit_after>//------------------------------------------------------------------------------
/// \file  string.cpp
//------------------------------------------------------------------------------
/// \brief Implementation of general purpose functions for string processing
//------------------------------------------------------------------------------
// Copyright (c) 2010 Serge Aleynikov <saleyn@gmail.com>
// Created: 2010-05-06
//------------------------------------------------------------------------------
/*
***** BEGIN LICENSE BLOCK *****

This file is part of the utxx open-source project.

Copyright (C) 2010 Serge Aleynikov <saleyn@gmail.com>

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

***** END LICENSE BLOCK *****
*/

#include <utxx/string.hpp>
#include <utxx/print_opts.hpp>

namespace utxx {

std::string to_bin_string(const char* a_buf, size_t a_sz,
                          bool a_hex, bool a_readable, bool a_eol)
{
    std::stringstream out;
    const char* begin = a_buf, *end = a_buf + a_sz;
    print_opts  opts  = a_hex
                      ? (a_readable ? print_opts::printable_or_hex : print_opts::hex)
                      : (a_readable ? print_opts::printable_or_dec : print_opts::dec);
    output(out, begin, end, opts, ",", "", "\"", "<<", ">>");
    if (a_eol) out << std::endl;
    return out.str();
}

bool wildcard_match(const char* a_input, const char* a_pattern)
{
    // Pattern match a_input against a_pattern, and exit
    // at the end of the input string
    for (const char* ip = nullptr, *pp = nullptr; *a_input;)
        if (*a_pattern == '*') {
            if (!*++a_pattern)
                return true;    // Reached '*' at the end of pattern
            pp = a_pattern;     // Store matching state right after '*'
            ip = a_input;
        } else if ((*a_pattern == *a_input) || (*a_pattern == '?')) {
            a_pattern++;        // Continue successful input match
            a_input++;
        } else if (pp) {
            a_pattern = pp;     // Match failed - restore state of pattern after '*'
            a_input   = ++ip;   // Advance the input on every match failure
        } else
            return false;       // Match failed before the first '*' is found

    // Skip trailing '*' in the pattern, since they don't affect the outcome:
    while (*a_pattern == '*') a_pattern++;

    // This point is reached only when the a_input string was fully
    // exhaused. If at this point the a_pattern is exhaused too ('\0'),
    // there's a match, otherwise pattern match is incomplete.
    return !*a_pattern;
}

} // namespace utxx
<|endoftext|>


<commit_before>#include <vector>
#include <string>
#include <sstream>

#include "error_handling.h"
#include "game.h"
#include "coordinate.h"
#include "fight.h"
#include "io.h"
#include "item.h"
#include "level.h"
#include "misc.h"
#include "monster.h"
#include "options.h"
#include "os.h"
#include "player.h"
#include "rogue.h"

#include "weapons.h"

using namespace std;

static Weapon::Type random_weapon_type() {
  int value = os_rand_range(100);

  int end = static_cast<int>(Weapon::Type::NWEAPONS);
  for (int i = 0; i < end; ++i) {
    Weapon::Type type = static_cast<Weapon::Type>(i);
    int probability = Weapon::probability(type);

    if (value < probability) {
      return type;

    } else {
      value -= probability;
    }
  }

  error("Error! Sum of probabilities is not 100%");
}

class Weapon* Weapon::clone() const {
  return new Weapon(*this);
}

bool Weapon::is_magic() const {
  return get_hit_plus() != 0 || get_damage_plus() != 0;
}

Weapon::~Weapon() {}

Weapon::Weapon(bool random_stats) : Weapon(random_weapon_type(), random_stats) {}

Weapon::Weapon(Weapon::Type subtype_, bool random_stats)
  : Item(), subtype(subtype_), identified(false)  {

  o_type = IO::Weapon;
  o_which = subtype;
  o_count = 1;

  switch (subtype) {
    case MACE: {
      set_attack_damage({2,4});
      set_throw_damage({1,3});
      o_launch = NO_WEAPON;
    } break;

    case SWORD: {
      set_attack_damage({3,4});
      set_throw_damage({1,2});
      o_launch = NO_WEAPON;
    } break;

    case BOW: {
      set_attack_damage({1,1});
      set_throw_damage({2,3});
      o_launch = NO_WEAPON;
    } break;

    case ARROW: {
      set_attack_damage({0,0});
      set_throw_damage({1,1});
      o_launch = BOW;
      o_count = os_rand_range(8) + 8;
      o_flags = ISMANY|ISMISL;
      o_type = IO::Ammo;
    } break;

    case DAGGER: {
      set_attack_damage({1,6});
      set_throw_damage({1,4});
      o_launch = NO_WEAPON;
      o_count = os_rand_range(4) + 2;
      o_flags = ISMISL;
    } break;

    case TWOSWORD: {
      set_attack_damage({4,4});
      set_throw_damage({1,3});
      o_launch = NO_WEAPON;
    } break;

    case DART: {
      set_attack_damage({0,0});
      set_throw_damage({1,3});
      o_launch = NO_WEAPON;
      o_count = os_rand_range(8) + 8;
      o_flags = ISMANY|ISMISL;
      o_type = IO::Ammo;
    } break;

    case SHIRAKEN: {
      set_attack_damage({0,0});
      set_throw_damage({2,4});
      o_launch = NO_WEAPON;
      o_count = os_rand_range(8) + 8;
      o_flags = ISMANY|ISMISL;
      o_type = IO::Ammo;
    } break;

    case SPEAR: {
      set_attack_damage({2,3});
      set_throw_damage({1,6});
      set_armor(2);
      o_launch = NO_WEAPON;
      o_flags = ISMISL;
    } break;

    case NWEAPONS: error("Unknown type NWEAPONS");
    case NO_WEAPON: error("Unknown type NO_WEAPON");
  }

  if (random_stats) {
    int rand = os_rand_range(100);
    if (rand < 10) {
      set_cursed();
      modify_hit_plus(-os_rand_range(3) + 1);
    }
    else if (rand < 15) {
      modify_hit_plus(os_rand_range(3) + 1);
    }
  }
}

void Weapon::set_identified() {
  identified = true;
}

void Weapon::set_not_identified() {
  identified = false;
}

bool Weapon::is_identified() const {
  return identified;
}

string Weapon::name(Weapon::Type type) {
  switch (type) {
    case MACE:     return "mace";
    case SWORD:    return "long sword";
    case BOW:      return "short bow";
    case ARROW:    return "arrow";
    case DAGGER:   return "dagger";
    case TWOSWORD: return "two handed sword";
    case DART:     return "dart";
    case SHIRAKEN: return "shuriken";
    case SPEAR:    return "spear";
    case NWEAPONS: error("Unknown type NWEAPONS");
    case NO_WEAPON: error("Unknown type NO_WEAPON");
  }
}

int Weapon::probability(Weapon::Type type) {
  switch (type) {
    case MACE:     return 11;
    case SWORD:    return 11;
    case BOW:      return 12;
    case ARROW:    return 12;
    case DAGGER:   return  8;
    case TWOSWORD: return 10;
    case DART:     return 12;
    case SHIRAKEN: return 12;
    case SPEAR:    return 12;
    case NWEAPONS: error("Unknown type NWEAPONS");
    case NO_WEAPON: error("Unknown type NO_WEAPON");
  }
}

int Weapon::worth(Weapon::Type type) {
  switch (type) {
    case MACE:     return  8;
    case SWORD:    return 15;
    case BOW:      return 15;
    case ARROW:    return  1;
    case DAGGER:   return  3;
    case TWOSWORD: return 75;
    case DART:     return  2;
    case SHIRAKEN: return  5;
    case SPEAR:    return  5;
    case NWEAPONS: error("Unknown type NWEAPONS");
    case NO_WEAPON: error("Unknown type NO_WEAPON");
  }
}

string Weapon::get_description() const {
  stringstream buffer;

  string const& obj_name = Weapon::name(static_cast<Weapon::Type>(o_which));

  if (o_count == 1) {
    buffer << "a" << vowelstr(obj_name) << " " << obj_name;
  } else {
    buffer << o_count << " " << obj_name << "s";
  }

  int dices;
  int sides;
  if (o_type == IO::Ammo || o_which == Weapon::BOW) {
    dices = get_throw_damage().dices;
    sides = get_throw_damage().sides;
  } else if (o_type == IO::Weapon) {
    dices = get_attack_damage().dices;
    sides = get_attack_damage().sides;
  } else {
    error("Bad item type");
  }

  buffer << " (" << sides << "d" << dices << ")";

  if (identified) {
    buffer << " (";
    int p_hit = get_hit_plus();
    if (p_hit >= 0) {
      buffer << "+";
    }
    buffer << p_hit << ",";

    int p_dmg = get_damage_plus();
    if (p_dmg >= 0) {
      buffer << "+";
    }
    buffer << p_dmg << ")";
  }

  if (get_armor() != 0) {
    buffer << " [";
    int p_armor = get_armor();
    if (p_armor >= 0) {
      buffer << "+";
    }
    buffer << p_armor << "]";
  }

  if (!get_nickname().empty()) {
    buffer << " called " << get_nickname();
  }

  return buffer.str();
}

void
weapon_missile_fall(Item* obj, bool pr) {
  Coordinate fpos;

  if (fallpos(&obj->get_position(), &fpos)) {
    obj->set_position(fpos);

    // See if we can stack it with something on the ground
    for (Item* ground_item : Game::level->items) {
      if (ground_item->get_position() == obj->get_position() &&
          ground_item->o_type == obj->o_type &&
          ground_item->o_which == obj->o_which &&
          ground_item->get_hit_plus() == obj->get_hit_plus() &&
          ground_item->get_damage_plus() == obj->get_damage_plus()) {

        ground_item->o_count++;
        delete obj;
        obj = nullptr;
        break;
      }
    }

    if (obj != nullptr) {
      Game::level->items.push_back(obj);
    }
    return;
  }

  if (pr) {
    stringstream os;
    os << "the "
       << Weapon::name(static_cast<Weapon::Type>(obj->o_which))
       << " vanishes as it hits the ground";
    Game::io->message(os.str());
  }
  delete obj;
}

<commit_msg>Arrows should never display damage, only +1 and stuff<commit_after>#include <vector>
#include <string>
#include <sstream>

#include "error_handling.h"
#include "game.h"
#include "coordinate.h"
#include "fight.h"
#include "io.h"
#include "item.h"
#include "level.h"
#include "misc.h"
#include "monster.h"
#include "options.h"
#include "os.h"
#include "player.h"
#include "rogue.h"

#include "weapons.h"

using namespace std;

static Weapon::Type random_weapon_type() {
  int value = os_rand_range(100);

  int end = static_cast<int>(Weapon::Type::NWEAPONS);
  for (int i = 0; i < end; ++i) {
    Weapon::Type type = static_cast<Weapon::Type>(i);
    int probability = Weapon::probability(type);

    if (value < probability) {
      return type;

    } else {
      value -= probability;
    }
  }

  error("Error! Sum of probabilities is not 100%");
}

class Weapon* Weapon::clone() const {
  return new Weapon(*this);
}

bool Weapon::is_magic() const {
  return get_hit_plus() != 0 || get_damage_plus() != 0;
}

Weapon::~Weapon() {}

Weapon::Weapon(bool random_stats) : Weapon(random_weapon_type(), random_stats) {}

Weapon::Weapon(Weapon::Type subtype_, bool random_stats)
  : Item(), subtype(subtype_), identified(false)  {

  o_type = IO::Weapon;
  o_which = subtype;
  o_count = 1;

  switch (subtype) {
    case MACE: {
      set_attack_damage({2,4});
      set_throw_damage({1,3});
      o_launch = NO_WEAPON;
    } break;

    case SWORD: {
      set_attack_damage({3,4});
      set_throw_damage({1,2});
      o_launch = NO_WEAPON;
    } break;

    case BOW: {
      set_attack_damage({1,1});
      set_throw_damage({2,3});
      o_launch = NO_WEAPON;
    } break;

    case ARROW: {
      set_attack_damage({0,0});
      set_throw_damage({1,1});
      o_launch = BOW;
      o_count = os_rand_range(8) + 8;
      o_flags = ISMANY|ISMISL;
      o_type = IO::Ammo;
    } break;

    case DAGGER: {
      set_attack_damage({1,6});
      set_throw_damage({1,4});
      o_launch = NO_WEAPON;
      o_count = os_rand_range(4) + 2;
      o_flags = ISMISL;
    } break;

    case TWOSWORD: {
      set_attack_damage({4,4});
      set_throw_damage({1,3});
      o_launch = NO_WEAPON;
    } break;

    case DART: {
      set_attack_damage({0,0});
      set_throw_damage({1,3});
      o_launch = NO_WEAPON;
      o_count = os_rand_range(8) + 8;
      o_flags = ISMANY|ISMISL;
      o_type = IO::Ammo;
    } break;

    case SHIRAKEN: {
      set_attack_damage({0,0});
      set_throw_damage({2,4});
      o_launch = NO_WEAPON;
      o_count = os_rand_range(8) + 8;
      o_flags = ISMANY|ISMISL;
      o_type = IO::Ammo;
    } break;

    case SPEAR: {
      set_attack_damage({2,3});
      set_throw_damage({1,6});
      set_armor(2);
      o_launch = NO_WEAPON;
      o_flags = ISMISL;
    } break;

    case NWEAPONS: error("Unknown type NWEAPONS");
    case NO_WEAPON: error("Unknown type NO_WEAPON");
  }

  if (random_stats) {
    int rand = os_rand_range(100);
    if (rand < 10) {
      set_cursed();
      modify_hit_plus(-os_rand_range(3) + 1);
    }
    else if (rand < 15) {
      modify_hit_plus(os_rand_range(3) + 1);
    }
  }
}

void Weapon::set_identified() {
  identified = true;
}

void Weapon::set_not_identified() {
  identified = false;
}

bool Weapon::is_identified() const {
  return identified;
}

string Weapon::name(Weapon::Type type) {
  switch (type) {
    case MACE:     return "mace";
    case SWORD:    return "long sword";
    case BOW:      return "short bow";
    case ARROW:    return "arrow";
    case DAGGER:   return "dagger";
    case TWOSWORD: return "two handed sword";
    case DART:     return "dart";
    case SHIRAKEN: return "shuriken";
    case SPEAR:    return "spear";
    case NWEAPONS: error("Unknown type NWEAPONS");
    case NO_WEAPON: error("Unknown type NO_WEAPON");
  }
}

int Weapon::probability(Weapon::Type type) {
  switch (type) {
    case MACE:     return 11;
    case SWORD:    return 11;
    case BOW:      return 12;
    case ARROW:    return 12;
    case DAGGER:   return  8;
    case TWOSWORD: return 10;
    case DART:     return 12;
    case SHIRAKEN: return 12;
    case SPEAR:    return 12;
    case NWEAPONS: error("Unknown type NWEAPONS");
    case NO_WEAPON: error("Unknown type NO_WEAPON");
  }
}

int Weapon::worth(Weapon::Type type) {
  switch (type) {
    case MACE:     return  8;
    case SWORD:    return 15;
    case BOW:      return 15;
    case ARROW:    return  1;
    case DAGGER:   return  3;
    case TWOSWORD: return 75;
    case DART:     return  2;
    case SHIRAKEN: return  5;
    case SPEAR:    return  5;
    case NWEAPONS: error("Unknown type NWEAPONS");
    case NO_WEAPON: error("Unknown type NO_WEAPON");
  }
}

string Weapon::get_description() const {
  stringstream buffer;

  string const& obj_name = Weapon::name(static_cast<Weapon::Type>(o_which));

  if (o_count == 1) {
    buffer << "a" << vowelstr(obj_name) << " " << obj_name;
  } else {
    buffer << o_count << " " << obj_name << "s";
  }

  if (o_which == Weapon::BOW) {
    buffer
      << " (" << get_throw_damage().sides
      << "d"  << get_throw_damage().dices << ")";
  } else if (o_type == IO::Weapon) {
    buffer
      << " (" << get_attack_damage().sides
      << "d"  << get_attack_damage().dices << ")";
  }

  if (identified) {
    buffer << " (";
    int p_hit = get_hit_plus();
    if (p_hit >= 0) {
      buffer << "+";
    }
    buffer << p_hit << ",";

    int p_dmg = get_damage_plus();
    if (p_dmg >= 0) {
      buffer << "+";
    }
    buffer << p_dmg << ")";
  }

  if (get_armor() != 0) {
    buffer << " [";
    int p_armor = get_armor();
    if (p_armor >= 0) {
      buffer << "+";
    }
    buffer << p_armor << "]";
  }

  if (!get_nickname().empty()) {
    buffer << " called " << get_nickname();
  }

  return buffer.str();
}

void
weapon_missile_fall(Item* obj, bool pr) {
  Coordinate fpos;

  if (fallpos(&obj->get_position(), &fpos)) {
    obj->set_position(fpos);

    // See if we can stack it with something on the ground
    for (Item* ground_item : Game::level->items) {
      if (ground_item->get_position() == obj->get_position() &&
          ground_item->o_type == obj->o_type &&
          ground_item->o_which == obj->o_which &&
          ground_item->get_hit_plus() == obj->get_hit_plus() &&
          ground_item->get_damage_plus() == obj->get_damage_plus()) {

        ground_item->o_count++;
        delete obj;
        obj = nullptr;
        break;
      }
    }

    if (obj != nullptr) {
      Game::level->items.push_back(obj);
    }
    return;
  }

  if (pr) {
    stringstream os;
    os << "the "
       << Weapon::name(static_cast<Weapon::Type>(obj->o_which))
       << " vanishes as it hits the ground";
    Game::io->message(os.str());
  }
  delete obj;
}

<|endoftext|>


<commit_before>#include "window.h"
#include "game_engine_interface.h"
#include <iostream>

void Window::initialise (GameEngineInterface* a_engine, void* args, void* retval)
{
    m_engine    = a_engine;
    m_args      = args;
    m_retval    = retval;
    setDimensions (2, 2, 2, 2);
}

void Window::setDimensions (int x, int y, int width, int height)
{
    m_xOffset   = x;
    m_yOffset   = y;
    m_width     = width;
    m_height    = height;

    getEngine()->getGraphics()->calculateWindowOffsetsFromCentre (height, width, y, x);
    if (m_xOffset == 0) {
        m_xOffset = x;
    }
    if (m_yOffset == 0) {
        m_yOffset = y;
    }
}

unsigned int Window::drawString (int y, int x, const char* text, Color fg, Color bg)
{
    return getEngine()->getGraphics()->drawString (m_yOffset+y, m_xOffset+x, text, fg, bg);
}

void Window::drawTile (int y, int x, unsigned int tile, Color fg, Color bg)
{
    getEngine()->getGraphics()->drawTile (m_yOffset+y, m_xOffset+x, tile, fg, bg);
}

void Window::drawBorder (int y, int x, int height, int width) {
    getEngine()->getGraphics()->drawBorder (m_yOffset+y, m_xOffset+x, height, width);
}

void Window::clearArea (int y, int x, int height, int width) {
    getEngine()->getGraphics()->clearArea (m_yOffset+y, m_xOffset+x, height, width);
}

void Window::beforeRedraw()
{
    getEngine()->getGraphics()->clearArea (m_yOffset, m_xOffset, m_height, m_width);
    getEngine()->getGraphics()->drawBorder (m_yOffset, m_xOffset, m_height-2, m_width-2);

    int x, y;
    getEngine()->getGraphics()->calculateWindowOffsetsFromCentre (0, m_title.size(), y, x);
    getEngine()->getGraphics()->clearArea (m_yOffset, x, 1, m_title.size());
    drawString (0, x-m_xOffset, m_title.c_str());

}

void Window::afterRedraw()
{

}

void Window::destroy (void)
{

}

void Window::resize (int width, int height)
{

}

void Window::mouseDown (int x, int y, int button)
{
    if (button < MAX_BUTTONS) {
        m_buttons[button] = true;
    }
}

void Window::mouseUp (int x, int y, int button)
{
    if (button < MAX_BUTTONS) {
        m_buttons[button] = false;
    }
}

bool Window::getMouseButton (int button)
{
    if (button < MAX_BUTTONS) {
        return m_buttons[button];
    }
    return false;
}

void Window::drawProgress (unsigned int x, unsigned int y, unsigned int value, unsigned int max)
{
    float l_value = (float) value;
    float l_max = (float) max;
    Color l_color ((1.0f-(l_value/l_max)), l_value/l_max, 0);

    for (unsigned int xx = 0; xx < value; xx++) {
        drawTile (y, x+xx, 178, l_color, Color(BLACK));
    }
}

unsigned int Window::wrapText (const std::string& text, std::vector<std::string>& lines, unsigned int maxWidth, unsigned int maxRows)
{
    size_t wordStart = 0;
    size_t wordEnd = 0;
    unsigned int lineNum = 0;
    lines.resize (maxRows);

    while (wordEnd != std::string::npos) {
        wordEnd = text.find (' ', wordStart);
        std::string word (text.substr (wordStart, wordEnd-wordStart));
        std::cout << "Word: " << word << std::endl;
        if (lines[lineNum].length() + word.length() + 1 > maxWidth) {
            if (lineNum + 1 >= maxRows) {
                lines[lineNum].append ("...");
                return lineNum;
            }
            // Start the next line
            lineNum++;
        }
        lines[lineNum].append (word);
        lines[lineNum].append (" ");
        wordStart = wordEnd+1;
        std::cout << "Line: " << lines[lineNum] << std::endl;
    }

    return lineNum;
}
<commit_msg>Now end of line calculation include the ...<commit_after>#include "window.h"
#include "game_engine_interface.h"
#include <iostream>

void Window::initialise (GameEngineInterface* a_engine, void* args, void* retval)
{
    m_engine    = a_engine;
    m_args      = args;
    m_retval    = retval;
    setDimensions (2, 2, 2, 2);
}

void Window::setDimensions (int x, int y, int width, int height)
{
    m_xOffset   = x;
    m_yOffset   = y;
    m_width     = width;
    m_height    = height;

    getEngine()->getGraphics()->calculateWindowOffsetsFromCentre (height, width, y, x);
    if (m_xOffset == 0) {
        m_xOffset = x;
    }
    if (m_yOffset == 0) {
        m_yOffset = y;
    }
}

unsigned int Window::drawString (int y, int x, const char* text, Color fg, Color bg)
{
    return getEngine()->getGraphics()->drawString (m_yOffset+y, m_xOffset+x, text, fg, bg);
}

void Window::drawTile (int y, int x, unsigned int tile, Color fg, Color bg)
{
    getEngine()->getGraphics()->drawTile (m_yOffset+y, m_xOffset+x, tile, fg, bg);
}

void Window::drawBorder (int y, int x, int height, int width) {
    getEngine()->getGraphics()->drawBorder (m_yOffset+y, m_xOffset+x, height, width);
}

void Window::clearArea (int y, int x, int height, int width) {
    getEngine()->getGraphics()->clearArea (m_yOffset+y, m_xOffset+x, height, width);
}

void Window::beforeRedraw()
{
    getEngine()->getGraphics()->clearArea (m_yOffset, m_xOffset, m_height, m_width);
    getEngine()->getGraphics()->drawBorder (m_yOffset, m_xOffset, m_height-2, m_width-2);

    int x, y;
    getEngine()->getGraphics()->calculateWindowOffsetsFromCentre (0, m_title.size(), y, x);
    getEngine()->getGraphics()->clearArea (m_yOffset, x, 1, m_title.size());
    drawString (0, x-m_xOffset, m_title.c_str());

}

void Window::afterRedraw()
{

}

void Window::destroy (void)
{

}

void Window::resize (int width, int height)
{

}

void Window::mouseDown (int x, int y, int button)
{
    if (button < MAX_BUTTONS) {
        m_buttons[button] = true;
    }
}

void Window::mouseUp (int x, int y, int button)
{
    if (button < MAX_BUTTONS) {
        m_buttons[button] = false;
    }
}

bool Window::getMouseButton (int button)
{
    if (button < MAX_BUTTONS) {
        return m_buttons[button];
    }
    return false;
}

void Window::drawProgress (unsigned int x, unsigned int y, unsigned int value, unsigned int max)
{
    float l_value = (float) value;
    float l_max = (float) max;
    Color l_color ((1.0f-(l_value/l_max)), l_value/l_max, 0);

    for (unsigned int xx = 0; xx < value; xx++) {
        drawTile (y, x+xx, 178, l_color, Color(BLACK));
    }
}

unsigned int Window::wrapText (const std::string& text, std::vector<std::string>& lines, unsigned int maxWidth, unsigned int maxRows)
{
    size_t wordStart = 0;
    size_t wordEnd = 0;
    unsigned int lineNum = 0;
    lines.resize (maxRows);

    while (wordEnd != std::string::npos) {
        wordEnd = text.find (' ', wordStart);
        std::string word (text.substr (wordStart, wordEnd-wordStart));
        if (lines[lineNum].length() + word.length() + 3 /*...*/ + 2 /*spaces*/ > maxWidth && lineNum + 1 >= maxRows) {
            lines[lineNum].append ("...");
            return lineNum;
        }
        if (lines[lineNum].length() + word.length() + 1 > maxWidth) {
            if (lineNum + 1 >= maxRows) {
                lines[lineNum].append ("...");
                return lineNum;
            }
            // Start the next line
            lineNum++;
        }
        lines[lineNum].append (word);
        lines[lineNum].append (" ");
        wordStart = wordEnd+1;
    }

    return lineNum;
}
<|endoftext|>


<commit_before>#include <array>

#include "core/image.h"
#include "core/image_draw.h"
#include "core/io.h"
#include "core/identicon.h"
#include "core/hashgen_retro.h"
#include "core/hashgen_sprator.h"
#include "core/argparse.h"
#include "core/random.h"
#include "core/str.h"
#include "core/collage.h"
#include "core/palette.h"

using namespace euphoria::core;

enum class HashType
{
    Identicon, Retro, Sprator
};

struct CommonArguments
{
    int image_size = 512;
    int number_of_images = 10;
    bool use_random = true;
    HashType type = HashType::Identicon;

    explicit CommonArguments(argparse::ParserBase* base)
    {
        base->Add("--size", &image_size).Help("image size");
        base->Add("--count", &number_of_images).Help("The number of images to generate");
        base->SetFalse("--const", &use_random).Help("Use a constant value");
        base->Add("-t", &type).Help("Set the type to use");
    }
};

const auto PALETTE = Palette
{
    "",
    Color::Red,
    Color::White,
    Color::Blue,

    Color::LightGreen,
    Color::Yellow,
    Color::LightBlue,

    Color::Pink,
    Color::Orange,
    Color::Tan,

    Color::Brown,
    Color::Green,
    Color::Purple,
    Color::CornflowerBlue,
    Color::Cyan
};

void RunMain
(
    int image_size,
    int number_of_images,
    bool use_random,
    HashType type,
    bool collage
)
{
    if(use_random==false && number_of_images > 1)
    {
        std::cout << "Since random isn't requested: setting the number of images to 1...\n";
        number_of_images = 1;
    }

    Random random;

    auto images = std::vector<Image>{};
    Image image;
    image.SetupWithAlphaSupport(image_size, image_size);

    for(int i = 0; i < number_of_images; i += 1)
    {
        int code = -2044886870;
        if(use_random)
        {
            code = random.NextInteger();
        }

        switch(type)
        {
        case HashType::Identicon:
            RenderIdenticon(&image, code);
            break;
        case HashType::Retro:
            RenderRetro(&image, code);
            break;
        case HashType::Sprator:
            RenderSprator(&image, code, PALETTE.GetSafeIndex(i));
            break;
        default:
            DIE("Unhandled type");
            break;
        }

        std::string file_name = "identicon.png";

        if(collage)
        {
            images.emplace_back(image);
            std::cout << "Generated collage image\n";
        }
        else
        {
            if(number_of_images > 1)
            {
                file_name = Str() << "identicon_" << (i + 1) << ".png";
                std::cout << "Writing " << file_name << "\n";
            }

            io::ChunkToFile(image.Write(ImageWriteFormat::PNG), file_name);
        }
    }

    if(collage)
    {
        std::cout << "writing collage...\n";
        int padding = 20;
        auto collage_image = GridLayout(images, padding, Color::Gray, true);
        std::string file_name = "identicon.png";
        io::ChunkToFile(collage_image.Write(ImageWriteFormat::PNG), file_name);
    }
}

void RunSpratorCollage
(
    int image_size,
    int number_of_images,
    int frames
)
{
    Random random;
    auto sprites = std::vector<std::vector<Image>>{};

    for(int image_index = 0; image_index < number_of_images; image_index += 1)
    {
        auto image_frames = std::vector<Image>{};
        for(int frame_index = 0; frame_index < frames; frame_index +=1)
        {
            Image image;
            image.SetupWithAlphaSupport(image_size, image_size);
            image_frames.emplace_back(image);
        }

        const int code = random.NextInteger();
        RenderSprator(&image_frames, code, PALETTE.GetSafeIndex(image_index));

        sprites.emplace_back(image_frames);
        std::cout << "Generated collage image\n";
    }

    const auto c = Max(frames-2, 0);
    const auto write_frames = c + c*2 + 1;
    for(int image_index = 0; image_index < write_frames; image_index +=1)
    {
        const auto frame_index = (image_index % 2 == 0) ? 0 : (image_index+1) / 2;

        auto images = std::vector<Image>{};
        for(int image_index = 0; image_index < number_of_images; image_index += 1)
        {
            images.emplace_back(sprites[image_index][frame_index]);
        }

        std::cout << "writing collage...\n";
        int padding = 20;
        auto collage_image = GridLayout(images, padding, Color::Gray, true);
        std::string file_name = "identicon.png";
        if(frames > 1)
        {
            file_name = Str() << "identicon_" << image_index << ".png";
        }
        io::ChunkToFile(collage_image.Write(ImageWriteFormat::PNG), file_name);
    }
}

int
main(int argc, char* argv[])
{
    auto parser = argparse::Parser {"identicon test"};
    auto subs = parser.AddSubParsers();

    subs->Add
    (
        "singles", "write many images",
        [](argparse::SubParser* sub)
        {
            auto arguments = CommonArguments{sub};
            return sub->OnComplete
            (
                [&]
                {
                    RunMain
                    (
                        arguments.image_size,
                        arguments.number_of_images,
                        arguments.use_random,
                        arguments.type,
                        false
                    );
                    return argparse::ParseResult::Ok;
                }
            );
        }
    );
    subs->Add
    (
        "collage", "write collage",
        [](argparse::SubParser* sub)
        {
            auto arguments = CommonArguments{sub};
            return sub->OnComplete
            (
                [&]
                {
                    RunMain
                    (
                        arguments.image_size,
                        arguments.number_of_images,
                        arguments.use_random,
                        arguments.type,
                        true
                    );
                    return argparse::ParseResult::Ok;
                }
            );
        }
    );
    subs->Add
    (
        "sprator", "write sprator collage",
        [](argparse::SubParser* sub)
        {
            int image_size = 100;
            int number_of_images = 9;
            int frames = 3;

            sub->Add("--size", &image_size).Help("Image size");
            sub->Add("--images", &number_of_images).Help("the number of sprators");
            sub->Add("--frames", &frames).Help("the number of anim frames");

            return sub->OnComplete
            (
                [&]
                {
                    RunSpratorCollage
                    (
                        image_size,
                        number_of_images,
                        frames
                    );
                    return argparse::ParseResult::Ok;
                }
            );
        }
    );

    return argparse::ParseFromMain(&parser, argc, argv);
}

<commit_msg>better name that doesn't cause warning<commit_after>#include <array>

#include "core/image.h"
#include "core/image_draw.h"
#include "core/io.h"
#include "core/identicon.h"
#include "core/hashgen_retro.h"
#include "core/hashgen_sprator.h"
#include "core/argparse.h"
#include "core/random.h"
#include "core/str.h"
#include "core/collage.h"
#include "core/palette.h"

using namespace euphoria::core;

enum class HashType
{
    Identicon, Retro, Sprator
};

struct CommonArguments
{
    int image_size = 512;
    int number_of_images = 10;
    bool use_random = true;
    HashType type = HashType::Identicon;

    explicit CommonArguments(argparse::ParserBase* base)
    {
        base->Add("--size", &image_size).Help("image size");
        base->Add("--count", &number_of_images).Help("The number of images to generate");
        base->SetFalse("--const", &use_random).Help("Use a constant value");
        base->Add("-t", &type).Help("Set the type to use");
    }
};

const auto PALETTE = Palette
{
    "",
    Color::Red,
    Color::White,
    Color::Blue,

    Color::LightGreen,
    Color::Yellow,
    Color::LightBlue,

    Color::Pink,
    Color::Orange,
    Color::Tan,

    Color::Brown,
    Color::Green,
    Color::Purple,
    Color::CornflowerBlue,
    Color::Cyan
};

void RunMain
(
    int image_size,
    int number_of_images,
    bool use_random,
    HashType type,
    bool collage
)
{
    if(use_random==false && number_of_images > 1)
    {
        std::cout << "Since random isn't requested: setting the number of images to 1...\n";
        number_of_images = 1;
    }

    Random random;

    auto images = std::vector<Image>{};
    Image image;
    image.SetupWithAlphaSupport(image_size, image_size);

    for(int i = 0; i < number_of_images; i += 1)
    {
        int code = -2044886870;
        if(use_random)
        {
            code = random.NextInteger();
        }

        switch(type)
        {
        case HashType::Identicon:
            RenderIdenticon(&image, code);
            break;
        case HashType::Retro:
            RenderRetro(&image, code);
            break;
        case HashType::Sprator:
            RenderSprator(&image, code, PALETTE.GetSafeIndex(i));
            break;
        default:
            DIE("Unhandled type");
            break;
        }

        std::string file_name = "identicon.png";

        if(collage)
        {
            images.emplace_back(image);
            std::cout << "Generated collage image\n";
        }
        else
        {
            if(number_of_images > 1)
            {
                file_name = Str() << "identicon_" << (i + 1) << ".png";
                std::cout << "Writing " << file_name << "\n";
            }

            io::ChunkToFile(image.Write(ImageWriteFormat::PNG), file_name);
        }
    }

    if(collage)
    {
        std::cout << "writing collage...\n";
        int padding = 20;
        auto collage_image = GridLayout(images, padding, Color::Gray, true);
        std::string file_name = "identicon.png";
        io::ChunkToFile(collage_image.Write(ImageWriteFormat::PNG), file_name);
    }
}

void RunSpratorCollage
(
    int image_size,
    int number_of_images,
    int frames
)
{
    Random random;
    auto sprites = std::vector<std::vector<Image>>{};

    for(int image_index = 0; image_index < number_of_images; image_index += 1)
    {
        auto image_frames = std::vector<Image>{};
        for(int frame_index = 0; frame_index < frames; frame_index +=1)
        {
            Image image;
            image.SetupWithAlphaSupport(image_size, image_size);
            image_frames.emplace_back(image);
        }

        const int code = random.NextInteger();
        RenderSprator(&image_frames, code, PALETTE.GetSafeIndex(image_index));

        sprites.emplace_back(image_frames);
        std::cout << "Generated collage image\n";
    }

    const auto c = Max(frames-2, 0);
    const auto write_frames = c + c*2 + 1;
    for(int anim_index = 0; anim_index < write_frames; anim_index +=1)
    {
        const auto frame_index = (anim_index % 2 == 0) ? 0 : (anim_index+1) / 2;

        auto images = std::vector<Image>{};
        for(int image_index = 0; image_index < number_of_images; image_index += 1)
        {
            images.emplace_back(sprites[image_index][frame_index]);
        }

        std::cout << "writing collage...\n";
        int padding = 20;
        auto collage_image = GridLayout(images, padding, Color::Gray, true);
        std::string file_name = "identicon.png";
        if(frames > 1)
        {
            file_name = Str() << "identicon_" << anim_index << ".png";
        }
        io::ChunkToFile(collage_image.Write(ImageWriteFormat::PNG), file_name);
    }
}

int
main(int argc, char* argv[])
{
    auto parser = argparse::Parser {"identicon test"};
    auto subs = parser.AddSubParsers();

    subs->Add
    (
        "singles", "write many images",
        [](argparse::SubParser* sub)
        {
            auto arguments = CommonArguments{sub};
            return sub->OnComplete
            (
                [&]
                {
                    RunMain
                    (
                        arguments.image_size,
                        arguments.number_of_images,
                        arguments.use_random,
                        arguments.type,
                        false
                    );
                    return argparse::ParseResult::Ok;
                }
            );
        }
    );
    subs->Add
    (
        "collage", "write collage",
        [](argparse::SubParser* sub)
        {
            auto arguments = CommonArguments{sub};
            return sub->OnComplete
            (
                [&]
                {
                    RunMain
                    (
                        arguments.image_size,
                        arguments.number_of_images,
                        arguments.use_random,
                        arguments.type,
                        true
                    );
                    return argparse::ParseResult::Ok;
                }
            );
        }
    );
    subs->Add
    (
        "sprator", "write sprator collage",
        [](argparse::SubParser* sub)
        {
            int image_size = 100;
            int number_of_images = 9;
            int frames = 3;

            sub->Add("--size", &image_size).Help("Image size");
            sub->Add("--images", &number_of_images).Help("the number of sprators");
            sub->Add("--frames", &frames).Help("the number of anim frames");

            return sub->OnComplete
            (
                [&]
                {
                    RunSpratorCollage
                    (
                        image_size,
                        number_of_images,
                        frames
                    );
                    return argparse::ParseResult::Ok;
                }
            );
        }
    );

    return argparse::ParseFromMain(&parser, argc, argv);
}

<|endoftext|>


<commit_before>/******************************************************************************
 *                   ____     ______   ____     __  __                        *
 *                  /\  _`\  /\  _  \ /\  _`\  /\ \/\ \                       *
 *                  \ \,\L\_\\ \ \L\ \\ \,\L\_\\ \ \_\ \                      *
 *                   \/_\__ \ \ \  __ \\/_\__ \ \ \  _  \                     *
 *                     /\ \L\ \\ \ \/\ \ /\ \L\ \\ \ \ \ \                    *
 *                     \ `\____\\ \_\ \_\\ `\____\\ \_\ \_\                   *
 *                      \/_____/ \/_/\/_/ \/_____/ \/_/\/_/                   *
 *                                                                            *
 *                                                                            *
 * Copyright (c) 2014                                                         *
 * Matthias Vallentin <vallentin (at) icir.org>                               *
 * Dominik Charousset <dominik.charousset (at) haw-hamburg.de>                *
 *                                                                            *
 * Distributed under the 3-clause BSD License.                                *
 * See accompanying file LICENSE.                                             *
\******************************************************************************/

#ifndef SASH_VARIABLES_ENGINE_HPP
#define SASH_VARIABLES_ENGINE_HPP

#include <map>
#include <string>
#include <iterator>
#include <algorithm>

namespace sash {

/// An example implementation for a variables engine that is
/// convertible to a std::function object.
template<typename Container = std::map<std::string, std::string>>
class variables_engine
{
public:
  /// The type of a std::function wrapper.
  using functor = std::function<void (std::string&,
                                      const std::string&,
                                      std::string&)>;

  /// Parses an input line and replaces all variables in the output.
  void parse(std::string& err, const std::string& in,
             std::string& out, bool sub_parse = false)
  {
    auto valid_varname_char = [](char c)
    {
      return std::isalnum(c) || c == '_';
    };
    using iter = typename std::string::const_iterator;
    char c = '\0'; // current character
    char lastc = ' '; // the last character, needed to distinct "$" from "\$"
    iter pos = in.begin(); // our current position in the stream
    iter last = in.end();
    enum
    {
        // traversing input, copying characters as we go
        traverse,
        // just read a $ indicating the start of a variable name
        after_dollar_sign,
        // read a variable name in the form of $name
        read_variable,
        // read a variable name in the form of ${name}
        read_braced_variable
    }
    state = traverse;
    auto i = in.begin();
    raii_error_string scoped_err{err};
    auto set_error = [&]() -> std::ostream&
    {
      return scoped_err.oss << "syntax error at position "
                            << std::to_string(std::distance(in.begin(), i))
                            << ": ";
    };
    auto flush = [&]() -> bool
    {
        switch (state)
        {
          case traverse:
            if (pos != last)
              out.insert(out.end(), pos, i);
            return true;
          case after_dollar_sign:
            if (i == last)
            {
              set_error() << "$ at end of line";
            }
            else if (*i == '$')
            {
              set_error() << "$$ is not a valid expression";
            }
            else
            {
              set_error() << "unexpected character '"
                          << *i << "' after $";
            }
            out.clear();
            return false;
          // pos is always set to the first character of the variable name,
          // i is always set to the first character that's not part of it
          case read_braced_variable:
            if (! valid_varname_char(c) && c != '}')
            {
              set_error() << "'" << c
                          << "' is an invalid character inside ${...}";
              return false;
            }
            // else:: fall through
          case read_variable:
            std::string varname(pos, i);
            auto j = variables_.find(varname);
            out += j == variables_.end() ? "" : j->second;
            state = traverse;
            if (state == read_braced_variable)
              pos = i + 1;
            else
              pos = i;
            return true;
        }
        return false; // should be unreachable
    };
    while (i != last)
    {
      c = *i;
      switch (c)
      {
        case '=':
          // assignment lines are parsed as '([a-zA-Z0-9_]+)=(.+)' => check
          if (! sub_parse && i != pos && pos == in.begin()
              && std::all_of(pos, i, valid_varname_char))
          {
              std::string key(pos, i);
              std::string val_input(i + 1, in.end());
              std::string value;
              // assignments don't produce an output
              out.clear();
              // our value can in turn have variables
              parse(err, val_input, value, true);
              if (err.empty())
                variables_.emplace(std::move(key), std::move(value));
              return;
          }
          break;
        case '$':
          if (lastc == '\\')
            break;
          // write previous input
          if (! flush())
            return;
          state = after_dollar_sign;
          pos = i + 1;
          break;
        case '{':
          if (state == after_dollar_sign)
          {
            pos = i + 1; // '{' is not part of the variable name
            state = read_braced_variable;
          }
          break;
        case '}':
          if (state == read_braced_variable)
          {
            if (! flush())
              return;
            pos = i + 1; // '}' won't be part of the output
            break;
          }
          // else: fall through
        default:
          if (! valid_varname_char(c) && state != traverse)
          {
            if (! flush())
              return;
          }
          else if (state == after_dollar_sign)
          {
            pos = i;
            state = read_variable;
          }
          break;
      }
      lastc = c;
      ++i;
    }
    if (state == read_braced_variable)
    {
      err = "syntax error: missing '}' at end of line";
    }
    flush();
  }

  /// Factory function to create a std::function using this implementation.
  /// @param predef A set of predefined variables to initialize the engine.
  static functor create(Container predef = Container{})
  {
    auto ptr = std::make_shared<variables_engine>();
    ptr->variables_ = std::move(predef);
    return [ptr](std::string& err, const std::string& in, std::string& out)
    {
      ptr->parse(err, in, out);
    };
  }

private:
  struct raii_error_string
  {
    raii_error_string(std::string& ref) : err(ref)
    {
      // nop
    }
    ~raii_error_string()
    {
      // leave err untouched if no error occured
      auto str = oss.str();
      if (! str.empty())
        err = std::move(str);
    }
    std::ostringstream oss;
    std::string& err;
  };

  Container variables_;
};

} // namespace sash

#endif // SASH_VARIABLES_ENGINE_HPP
<commit_msg>Allow setting/unsetting of variables directly<commit_after>/******************************************************************************
 *                   ____     ______   ____     __  __                        *
 *                  /\  _`\  /\  _  \ /\  _`\  /\ \/\ \                       *
 *                  \ \,\L\_\\ \ \L\ \\ \,\L\_\\ \ \_\ \                      *
 *                   \/_\__ \ \ \  __ \\/_\__ \ \ \  _  \                     *
 *                     /\ \L\ \\ \ \/\ \ /\ \L\ \\ \ \ \ \                    *
 *                     \ `\____\\ \_\ \_\\ `\____\\ \_\ \_\                   *
 *                      \/_____/ \/_/\/_/ \/_____/ \/_/\/_/                   *
 *                                                                            *
 *                                                                            *
 * Copyright (c) 2014                                                         *
 * Matthias Vallentin <vallentin (at) icir.org>                               *
 * Dominik Charousset <dominik.charousset (at) haw-hamburg.de>                *
 *                                                                            *
 * Distributed under the 3-clause BSD License.                                *
 * See accompanying file LICENSE.                                             *
\******************************************************************************/

#ifndef SASH_VARIABLES_ENGINE_HPP
#define SASH_VARIABLES_ENGINE_HPP

#include <map>
#include <string>
#include <iterator>
#include <algorithm>

namespace sash {

/// An example implementation for a variables engine that is
/// convertible to a std::function object.
template<typename Container = std::map<std::string, std::string>>
class variables_engine
{
public:
  /// The type of a std::function wrapper.
  using functor = std::function<void (std::string&,
                                      const std::string&,
                                      std::string&)>;

  /// Parses an input line and replaces all variables in the output.
  void parse(std::string& err, const std::string& in,
             std::string& out, bool sub_parse = false)
  {
    auto valid_varname_char = [](char c)
    {
      return std::isalnum(c) || c == '_';
    };
    using iter = typename std::string::const_iterator;
    char c = '\0'; // current character
    char lastc = ' '; // the last character, needed to distinct "$" from "\$"
    iter pos = in.begin(); // our current position in the stream
    iter last = in.end();
    enum
    {
        // traversing input, copying characters as we go
        traverse,
        // just read a $ indicating the start of a variable name
        after_dollar_sign,
        // read a variable name in the form of $name
        read_variable,
        // read a variable name in the form of ${name}
        read_braced_variable
    }
    state = traverse;
    auto i = in.begin();
    raii_error_string scoped_err{err};
    auto set_error = [&]() -> std::ostream&
    {
      return scoped_err.oss << "syntax error at position "
                            << std::to_string(std::distance(in.begin(), i))
                            << ": ";
    };
    auto flush = [&]() -> bool
    {
        switch (state)
        {
          case traverse:
            if (pos != last)
              out.insert(out.end(), pos, i);
            return true;
          case after_dollar_sign:
            if (i == last)
            {
              set_error() << "$ at end of line";
            }
            else if (*i == '$')
            {
              set_error() << "$$ is not a valid expression";
            }
            else
            {
              set_error() << "unexpected character '"
                          << *i << "' after $";
            }
            out.clear();
            return false;
          // pos is always set to the first character of the variable name,
          // i is always set to the first character that's not part of it
          case read_braced_variable:
            if (! valid_varname_char(c) && c != '}')
            {
              set_error() << "'" << c
                          << "' is an invalid character inside ${...}";
              return false;
            }
            // else:: fall through
          case read_variable:
            std::string varname(pos, i);
            auto j = variables_.find(varname);
            out += j == variables_.end() ? "" : j->second;
            state = traverse;
            if (state == read_braced_variable)
              pos = i + 1;
            else
              pos = i;
            return true;
        }
        return false; // should be unreachable
    };
    while (i != last)
    {
      c = *i;
      switch (c)
      {
        case '=':
          // assignment lines are parsed as '([a-zA-Z0-9_]+)=(.+)' => check
          if (! sub_parse && i != pos && pos == in.begin()
              && std::all_of(pos, i, valid_varname_char))
          {
              std::string key(pos, i);
              std::string val_input(i + 1, in.end());
              std::string value;
              // assignments don't produce an output
              out.clear();
              // our value can in turn have variables
              parse(err, val_input, value, true);
              if (err.empty())
                variables_.emplace(std::move(key), std::move(value));
              return;
          }
          break;
        case '$':
          if (lastc == '\\')
            break;
          // write previous input
          if (! flush())
            return;
          state = after_dollar_sign;
          pos = i + 1;
          break;
        case '{':
          if (state == after_dollar_sign)
          {
            pos = i + 1; // '{' is not part of the variable name
            state = read_braced_variable;
          }
          break;
        case '}':
          if (state == read_braced_variable)
          {
            if (! flush())
              return;
            pos = i + 1; // '}' won't be part of the output
            break;
          }
          // else: fall through
        default:
          if (! valid_varname_char(c) && state != traverse)
          {
            if (! flush())
              return;
          }
          else if (state == after_dollar_sign)
          {
            pos = i;
            state = read_variable;
          }
          break;
      }
      lastc = c;
      ++i;
    }
    if (state == read_braced_variable)
    {
      err = "syntax error: missing '}' at end of line";
    }
    flush();
  }

  /// Sets a variable to given value.
  void set(const std::string& identifier, std::string value)
  {
    variables_[identifier] = std::move(value);
  }

  /// Unsets a variable.
  void unset(const std::string& identifier)
  {
    variables_.erase(identifier);
  }

  /// Factory function to create a std::function using this implementation.
  /// @param predef A set of predefined variables to initialize the engine.
  static functor create(Container predef = Container{})
  {
    auto ptr = std::make_shared<variables_engine>();
    ptr->variables_ = std::move(predef);
    return [ptr](std::string& err, const std::string& in, std::string& out)
    {
      ptr->parse(err, in, out);
    };
  }

private:
  struct raii_error_string
  {
    raii_error_string(std::string& ref) : err(ref)
    {
      // nop
    }
    ~raii_error_string()
    {
      // leave err untouched if no error occured
      auto str = oss.str();
      if (! str.empty())
        err = std::move(str);
    }
    std::ostringstream oss;
    std::string& err;
  };

  Container variables_;
};

} // namespace sash

#endif // SASH_VARIABLES_ENGINE_HPP
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015 deipi.com LLC and contributors. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include "xapiand.h"

#include "utils.h"
#include "manager.h"

#include <stdlib.h>

XapiandManager *manager_ptr = NULL;

static void sig_shutdown_handler(int sig)
{
	if (manager_ptr) {
		manager_ptr->sig_shutdown_handler(sig);
	}
}

void setup_signal_handlers(void) {
	signal(SIGHUP, SIG_IGN);
	signal(SIGPIPE, SIG_IGN);

	struct sigaction act;

	/* When the SA_SIGINFO flag is set in sa_flags then sa_sigaction is used.
	 * Otherwise, sa_handler is used. */
	sigemptyset(&act.sa_mask);
	act.sa_flags = 0;
	act.sa_handler = sig_shutdown_handler;
	sigaction(SIGTERM, &act, NULL);
	sigaction(SIGINT, &act, NULL);
}

void run(int num_servers, const char *cluster_name_, const char *discovery_group, int discovery_port, int http_port, int binary_port)
{
	ev::default_loop default_loop;

	setup_signal_handlers();

	XapiandManager manager(&default_loop, cluster_name_, discovery_group, discovery_port, http_port, binary_port);

	manager_ptr = &manager;

	manager.run(num_servers);

	manager_ptr = NULL;
}

int main(int argc, char **argv)
{
	int num_servers = 8;
	int discovery_port = 0;
	int http_port = 0;
	int binary_port = 0;
	const char *discovery_group = NULL;
	const char *cluster_name = "xapiand";
	const char *p;

	INFO((void *)NULL,
		"\n\n"
		"  __  __           _                 _\n"
		"  \\ \\/ /__ _ _ __ (_) __ _ _ __   __| |\n"
		"   \\  // _` | '_ \\| |/ _` | '_ \\ / _` |\n"
		"   /  \\ (_| | |_) | | (_| | | | | (_| |\n"
		"  /_/\\_\\__,_| .__/|_|\\__,_|_| |_|\\__,_|\n"
		"            |_|  v%s\n"
		"   [%s]\n"
		"          Using Xapian v%s\n\n", PACKAGE_VERSION, PACKAGE_BUGREPORT, XAPIAN_VERSION);

	INFO((void *)NULL, "Joined cluster: %s\n", cluster_name);

	// Prefer glass database
	if (setenv("XAPIAN_PREFER_GLASS", "1", false) == 0) {
		INFO((void *)NULL, "Enabled glass database.\n");
	}

	// Enable changesets
	if (setenv("XAPIAN_MAX_CHANGESETS", "10", false) == 0) {
		INFO((void *)NULL, "Database changesets set to 10.\n");
	}

	// Flush threshold increased
	int flush_threshold = 10000;  // Default is 10000 (if no set)
	p = getenv("XAPIAN_FLUSH_THRESHOLD");
	if (p) flush_threshold = atoi(p);
	if (flush_threshold < 100000 && setenv("XAPIAN_FLUSH_THRESHOLD", "100000", false) == 0) {
		INFO((void *)NULL, "Increased flush threshold to 100000 (it was originally set to %d).\n", flush_threshold);
	}

	time(&init_time);
	struct tm *timeinfo = localtime(&init_time);
	timeinfo->tm_hour   = 0;
	timeinfo->tm_min    = 0;
	timeinfo->tm_sec    = 0;
	int diff_t = (int)(init_time - mktime(timeinfo));
	b_time.minute = diff_t / SLOT_TIME_SECOND;
	b_time.second =  diff_t % SLOT_TIME_SECOND;

	if (argc > 2) {
		http_port = atoi(argv[1]);
		binary_port = atoi(argv[2]);
	}

	run(num_servers, cluster_name, discovery_group, discovery_port, http_port, binary_port);
	INFO((void *)NULL, "Done with all work!\n");

	return 0;
}
<commit_msg>Added BRASS support with XAPIAN_PREFER_BRASS<commit_after>/*
 * Copyright (C) 2015 deipi.com LLC and contributors. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include "xapiand.h"

#include "utils.h"
#include "manager.h"

#include <stdlib.h>

XapiandManager *manager_ptr = NULL;

static void sig_shutdown_handler(int sig)
{
	if (manager_ptr) {
		manager_ptr->sig_shutdown_handler(sig);
	}
}

void setup_signal_handlers(void) {
	signal(SIGHUP, SIG_IGN);
	signal(SIGPIPE, SIG_IGN);

	struct sigaction act;

	/* When the SA_SIGINFO flag is set in sa_flags then sa_sigaction is used.
	 * Otherwise, sa_handler is used. */
	sigemptyset(&act.sa_mask);
	act.sa_flags = 0;
	act.sa_handler = sig_shutdown_handler;
	sigaction(SIGTERM, &act, NULL);
	sigaction(SIGINT, &act, NULL);
}

void run(int num_servers, const char *cluster_name_, const char *discovery_group, int discovery_port, int http_port, int binary_port)
{
	ev::default_loop default_loop;

	setup_signal_handlers();

	XapiandManager manager(&default_loop, cluster_name_, discovery_group, discovery_port, http_port, binary_port);

	manager_ptr = &manager;

	manager.run(num_servers);

	manager_ptr = NULL;
}

int main(int argc, char **argv)
{
	int num_servers = 8;
	int discovery_port = 0;
	int http_port = 0;
	int binary_port = 0;
	const char *discovery_group = NULL;
	const char *cluster_name = "xapiand";
	const char *p;

	INFO((void *)NULL,
		"\n\n"
		"  __  __           _                 _\n"
		"  \\ \\/ /__ _ _ __ (_) __ _ _ __   __| |\n"
		"   \\  // _` | '_ \\| |/ _` | '_ \\ / _` |\n"
		"   /  \\ (_| | |_) | | (_| | | | | (_| |\n"
		"  /_/\\_\\__,_| .__/|_|\\__,_|_| |_|\\__,_|\n"
		"            |_|  v%s\n"
		"   [%s]\n"
		"          Using Xapian v%s\n\n", PACKAGE_VERSION, PACKAGE_BUGREPORT, XAPIAN_VERSION);

	INFO((void *)NULL, "Joined cluster: %s\n", cluster_name);

#ifdef XAPIAN_HAS_GLASS_BACKEND
	// Prefer glass database
	if (setenv("XAPIAN_PREFER_GLASS", "1", false) == 0) {
		INFO((void *)NULL, "Enabled glass database.\n");
	}
#elif XAPIAN_HAS_BRASS_BACKEND
	// Prefer brass database
	if (setenv("XAPIAN_PREFER_BRASS", "1", false) == 0) {
		INFO((void *)NULL, "Enabled brass database.\n");
	}
#endif

	// Enable changesets
	if (setenv("XAPIAN_MAX_CHANGESETS", "10", false) == 0) {
		INFO((void *)NULL, "Database changesets set to 10.\n");
	}

	// Flush threshold increased
	int flush_threshold = 10000;  // Default is 10000 (if no set)
	p = getenv("XAPIAN_FLUSH_THRESHOLD");
	if (p) flush_threshold = atoi(p);
	if (flush_threshold < 100000 && setenv("XAPIAN_FLUSH_THRESHOLD", "100000", false) == 0) {
		INFO((void *)NULL, "Increased flush threshold to 100000 (it was originally set to %d).\n", flush_threshold);
	}

	time(&init_time);
	struct tm *timeinfo = localtime(&init_time);
	timeinfo->tm_hour   = 0;
	timeinfo->tm_min    = 0;
	timeinfo->tm_sec    = 0;
	int diff_t = (int)(init_time - mktime(timeinfo));
	b_time.minute = diff_t / SLOT_TIME_SECOND;
	b_time.second =  diff_t % SLOT_TIME_SECOND;

	if (argc > 2) {
		http_port = atoi(argv[1]);
		binary_port = atoi(argv[2]);
	}

	run(num_servers, cluster_name, discovery_group, discovery_port, http_port, binary_port);
	INFO((void *)NULL, "Done with all work!\n");

	return 0;
}
<|endoftext|>


<commit_before>
#include <iostream>
#include <fstream>
#include <iterator>

#include <steve/Language.hpp>
#include <steve/Lexer.hpp>
#include <steve/Parser.hpp>
#include <steve/Elaborator.hpp>

using namespace steve;

int
main() {
  Language lang;

  // Read the input text into a file.
  using Iter = std::istreambuf_iterator<char>;
  std::string text(Iter(std::cin), Iter());

  Lexer lex;
  Tokens toks = lex(text);
  for (const Token& k : toks)
    std::cout << debug(k) << ' ';
  std::cout << '\n';
  return 0;

  Parser parse;
  Tree* pt = parse(toks);
  if (not parse.diags.empty()) {
    std::cerr << "got errors\n" << parse.diags;
    return -1;
  }

  Elaborator elab;
  Expr* ast = elab(pt);
  if (not elab.diags.empty()) {
    std::cerr << "got typing errors\n" << elab.diags;
    return -1;
  }

  std::cout << debug(ast) << '\n';
}
<commit_msg>Comment out token printing.<commit_after>
#include <iostream>
#include <fstream>
#include <iterator>

#include <steve/Language.hpp>
#include <steve/Lexer.hpp>
#include <steve/Parser.hpp>
#include <steve/Elaborator.hpp>

using namespace steve;

int
main() {
  Language lang;

  // Read the input text into a file.
  using Iter = std::istreambuf_iterator<char>;
  std::string text(Iter(std::cin), Iter());

  Lexer lex;
  Tokens toks = lex(text);
  // for (const Token& k : toks)
  //   std::cout << debug(k) << ' ';
  // std::cout << '\n';
  // return 0;

  Parser parse;
  Tree* pt = parse(toks);
  if (not parse.diags.empty()) {
    std::cerr << "got errors\n" << parse.diags;
    return -1;
  }

  Elaborator elab;
  Expr* ast = elab(pt);
  if (not elab.diags.empty()) {
    std::cerr << "got typing errors\n" << elab.diags;
    return -1;
  }

  std::cout << debug(ast) << '\n';
}
<|endoftext|>