I have two classes MultiContainert and MultiContainerTest with Fixture:
My main problem is that some of my tests work well and return results, but after the "Remove" test, the terminal does not stop and display no message and or results, so I presume it blocks. My question is that I do not see where the problems would come from? I have no message to help me or guide me.
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/key.hpp>
#include <iostream>
#include <mutex>
#include <memory>
template <typename Tkey, typename Tval>
class MultiContainer
{
private:
using value_type = std::pair<Tkey, Tval>;
unsigned int capacity;
boost::multi_index_container<
value_type,
boost::multi_index::indexed_by<
boost::multi_index::sequenced<>,
boost::multi_index::hashed_unique<boost::multi_index::key<&value_type::first>>>>
container;
std::mutex mtx;
static std::unique_ptr<MultiContainer> instance;
MultiContainer(unsigned int icapacity) : capacity(icapacity) {}
public:
static MultiContainer &getInstance(unsigned int capacity)
{
if (!instance)
instance.reset(new MultiContainer(capacity));
return *instance;
}
int size()
{
std::lock_guard<std::mutex> lock(mtx);
return container.size();
}
bool isCapacityReached()
{
std::lock_guard<std::mutex> lock(mtx);
return container.size() >= capacity;
}
void removeLRU()
{
std::lock_guard<std::mutex> lock(mtx);
if (!container.empty())
container.erase(container.template get<0>().begin());
}
/*
void removeMRU()
{
std::lock_guardstd::mutex lock(mtx);
if (!container.empty())
container.erase(container.template get<0>().end() - 1);
}
*/
bool empty()
{
std::lock_guard<std::mutex> lock(mtx);
return container.empty();
}
void clear()
{
std::lock_guard<std::mutex> lock(mtx);
container.clear();
}
bool contains(const Tkey &key)
{
std::lock_guard<std::mutex> lock(mtx);
const auto &lookup = container.template get<1>();
return lookup.find(key) != lookup.end();
}
void remove(const Tkey &key)
{
std::lock_guard<std::mutex> lock(mtx);
auto &lookup = container.template get<1>();
lookup.erase(key);
}
void put(const Tkey &key, const Tval &val)
{
if (isCapacityReached())
{
std::lock_guard<std::mutex> lock(mtx);
removeLRU();
}
auto &lookup = container.template get<1>();
auto it = lookup.find(key);
if (it != lookup.end())
{
container.relocate(container.template get<0>().begin(), container.template project<0>(it));
lookup.modify(it, [&](value_type &x)
{ x.second = val; });
}
else
{
std::lock_guard<std::mutex> lock(mtx);
it = lookup.emplace(value_type(key, val)).first;
}
}
Tval get(const Tkey &key, const Tval &default_val = Tval())
{
std::lock_guard<std::mutex> lock(mtx);
const auto &lookup = container.template get<1>();
const auto it = lookup.find(key);
if (it == lookup.end())
{
return default_val;
}
container.relocate(container.template get<0>().begin(), container.template project<0>(it));
return it->second;
}
};
template <typename Tkey, typename Tval>
std::unique_ptr<MultiContainer<Tkey, Tval>> MultiContainer<Tkey, Tval>::instance = nullptr;
int main() {
MultiContainer<std::string, std::string> &container = MultiContainer<std::string, std::string>::getInstance(3);
container.put("key1", "value1");
container.put("key2", "value2");
container.put("key3", "value3");
std::cout << "Size : " << container.size() << std::endl;
std::cout << "Capacity reached : " << container.isCapacityReached() << std::endl;
std::cout << "Contains key1 : " << container.contains("key1") << std::endl;
std::cout << "Value for key1 : " << container.get("key1") << std::endl;
container.remove("key1");
std::cout << "Size : " << container.size() << std::endl;
std::cout << "Contains key1 : " << container.contains("key1") << std::endl;
container.clear();
std::cout << "Size : " << container.size() << std::endl;
std::cout << "Empty : " << container.empty() << std::endl;
return 0;
}
Classe MultiContainerTest:
#include <../googletest/include/gtest/gtest.h>
#include "multiContainer.hpp"
#include <chrono>
#include <thread>
class MultiContainerTest : public ::testing::Test
{
protected:
MultiContainer<int, std::string> &container = MultiContainer<int, std::string>::getInstance(3);
MultiContainer<int, std::string> &container2 = MultiContainer<int, std::string>::getInstance(5);
unsigned int cache_size = 1000;
MultiContainer<int, int> &cache = MultiContainer<int, int>::getInstance(cache_size);
virtual void TearDown()
{
cache.clear();
}
~MultiContainerTest() { } // remove exception specification
};
TEST_F(MultiContainerTest, CreateInstance)
{
EXPECT_EQ(container.size(), 0);
EXPECT_FALSE(container.isCapacityReached());
}
TEST_F(MultiContainerTest, Size)
{
container.put(1, "hello");
container.put(2, "world");
EXPECT_EQ(container.size(), 2);
}
TEST_F(MultiContainerTest, CapacityReached)
{
container.put(1, "hello");
container.put(2, "world");
container.put(3, "!");
EXPECT_TRUE(container.isCapacityReached());
}
TEST_F(MultiContainerTest, RemoveLRU)
{
container.put(1, "hello");
container.put(2, "world");
container.put(3, "!");
container.removeLRU();
EXPECT_FALSE(container.contains(1));
EXPECT_EQ(container.size(), 2);
}
TEST_F(MultiContainerTest, Empty)
{
EXPECT_TRUE(container.empty());
container.put(1, "hello");
EXPECT_FALSE(container.empty());
}
TEST_F(MultiContainerTest, Clear)
{
container.put(1, "hello");
container.put(2, "world");
container.clear();
EXPECT_TRUE(container.empty());
}
TEST_F(MultiContainerTest, Contains)
{
container.put(1, "hello");
container.put(2, "world");
EXPECT_TRUE(container.contains(1));
EXPECT_FALSE(container.contains(3));
}
TEST_F(MultiContainerTest, Remove)
{
container.put(1, "hello");
container.put(2, "world");
container.remove(1);
EXPECT_FALSE(container.contains(1));
EXPECT_EQ(container.size(), 1);
}
TEST_F(MultiContainerTest, CheckSingleton)
{
EXPECT_EQ(&container, &container2);
EXPECT_EQ(container.size(), container2.size());
container.put(1, "hello");
EXPECT_EQ(container2.get(1), "hello");
}
// Hit rate: the number of times an item is found in the cache divided by the total number of lookups
TEST_F(MultiContainerTest, HitRateTest)
{
int total_lookups = 1000000;
int hits = 0;
for (int i = 0; i < total_lookups; i++)
{
int key = rand() % cache_size;
int val = rand();
cache.put(key, val);
if (cache.contains(key))
{
hits++;
}
}
double hit_rate = (double)hits / total_lookups;
EXPECT_GT(hit_rate, 0.8);
}
TEST_F(MultiContainerTest, ConcurrencyTest)
{
std::vector<std::thread> threads;
for (int i = 0; i < 10; i++)
{
threads.push_back(std::thread([&]()
{
for (int j = 0; j < 100; j++)
{
int key = rand() % cache_size;
int val = rand();
cache.put(key, val);
} }));
}
for (auto &t : threads)
{
t.join();
}
// check that all elements are in the cache
for (int i = 0; i < cache_size; i++)
{
EXPECT_TRUE(cache.contains(i));
}
}
TEST_F(MultiContainerTest, TimeComplexityTest)
{
int num_elements = 100000;
auto start = std::chrono::high_resolution_clock::now();
for (int i = 0; i < num_elements; i++)
{
cache.put(i, i);
}
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
// check that the time taken to insert the elements is below a certain threshold
EXPECT_LT(duration.count(), 2000000);
}
TEST_F(MultiContainerTest, TimeComplexityGet)
{
int num_elements = 100000;
for (int i = 0; i < num_elements; i++)
{
cache.put(i, i);
}
auto start = std::chrono::high_resolution_clock::now();
for (int i = 0; i < num_elements; i++)
{
cache.get(i);
}
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
// check that the time taken to get the elements is below a certain threshold
EXPECT_LT(duration.count(), 2000000);
}
TEST_F(MultiContainerTest, TimeComplexityRemove)
{
int num_elements = 100000;
for (int i = 0; i < num_elements; i++)
{
cache.put(i, i);
}
auto start = std::chrono::high_resolution_clock::now();
for (int i = 0; i < num_elements; i++)
{
cache.remove(i);
}
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
// check that the time taken to remove the elements is below a certain threshold
EXPECT_LT(duration.count(), 2000000);
}
TEST_F(MultiContainerTest, TimeComplexityRemoveLRU)
{
int num_elements = 100000;
for (int i = 0; i < num_elements; i++)
{
cache.put(i, i);
}
auto start = std::chrono::high_resolution_clock::now();
for (int i = 0; i < num_elements; i++)
{
cache.removeLRU();
}
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
// check that the time taken to remove the LRU elements is below a certain threshold
EXPECT_LT(duration.count(), 2000000);
}
int main(int argc, char* argv[]) {
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
Related
I'm trying to count vowels in a book "War and Peace" by Lev Tolstoi with 4 different methods:
Using Count_if/find
Using Count_if/for
for/find
4.for/for
The programm also calculates time it takes for every method to get the number of vowels. I'm using a russian version of the book as a reference so all the vowels are taken from cyrillic alphabet. Here is the code:
#include <chrono>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
#include <Windows.h>
#include <string>
#include <fstream>
#include <iterator>
class Timer
{
private:
using clock_t = std::chrono::high_resolution_clock;
using second_t = std::chrono::duration<double, std::ratio<1> >;
std::string m_name;
std::chrono::time_point<clock_t> m_beg;
double elapsed() const
{
return std::chrono::duration_cast<second_t>(clock_t::now()
- m_beg).count();
}
public:
Timer() : m_beg(clock_t::now()) { }
Timer(std::string name) : m_name(name), m_beg(clock_t::now()) { }
void start(std::string name) {
m_name = name;
m_beg = clock_t::now();
}
void print() const {
std::cout << m_name << ":\t" << elapsed() * 1000 << " ms" << '\n';
}
};
const std::string vowels = "аеёиоуыэюяАЕЁИОУЫЭЮЯ";
bool containVowel(const std::string& s, const char& a)
{
for (size_t i = 0; i < s.size(); i++)
{
if (a == s[i])
{
return true;
}
return false;
}
}
void ForFor(std::ifstream& ifs, std::string& ww)
{
size_t count = 0;
Timer t1("for for");
while (ifs >> ww)
{
for (size_t i = 0; i < ww.size(); i++)
{
if (containVowel(vowels, ww[i]))
{
count++;
}
}
}
t1.print();
std::cout << count << std::endl;
}
//bool findVowel(char c)
//{
// return vowels.find(c) != std::string::npos;
//}
void CountIfFind(std::ifstream& ifs, std::string& ww) // not sure what is the way to cout count here...
{
Timer t("count_if/find");
while (ifs >> ww)
{
size_t count = std::count_if(ww.begin(), ww.end(), [&](char c) {return vowels.find(c) != std::string::npos; });
}
t.print();
}
void CountIfFor(std::ifstream& ifs, std::string& ww) // not sure what is the way to cout count here...
{
Timer t("count_if/for");
while (ifs >> ww)
{
for (size_t i = 0; i < vowels.size(); i++)
{
auto count = std::count_if(ww.begin(), ww.end(), [&](char c) {return c == vowels[i]; });
}
}
t.print();
}
void ForFind(std::ifstream& ifs, std::string& ww)
{
char c{};
int count = 0;
Timer t("for/find");
while (ifs >> ww)
{
for (size_t i = 0; i < ww.size(); i++)
{
if (vowels.find(c) != std::string::npos)
{
count++;
}
}
}
t.print();
std::cout << count << std::endl;
}
int main()
{
setlocale(LC_ALL, "ru");
SetConsoleCP(1251);
SetConsoleOutputCP(1251);
std::ifstream ifs;
ifs.open("Толстой Лев. Война и мир. Книга 1 - royallib.ru.txt");
if (ifs.is_open())
{
std::string ww;
ForFor(ifs, ww);
CountIfFind(ifs,ww);
CountIfFor(ifs,ww);
ForFind(ifs, ww);
ifs.close();
}
else
{
std::cout << "Can't open the file!" << std::endl;
}
}
Function ForFor works just fine but 3 other don't work (they don't show count but show time though). I'm guessing there is a problem with parsing the file, though I'm not sure because of my inexperience.
Will be hoping for your help!) Thank you all, in advance.
EDIT:Ok so now I'm sure the issue is in while(ifs>>ww). ForFor was the first function in the main so it worked, I tried commenting it and the next one CountIfFind started working. But when I delete while in every function and use it in main like: while(ifs>>ww) {ForFor(ww); CountIfFind(ww); CountIfFor(ww); ForFind(ww);} It doesn't work at all... How do I fix it?
So here is the correct way to do it:
class Timer
{
private:
using clock_t = std::chrono::high_resolution_clock;
using second_t = std::chrono::duration<double, std::ratio<1> >;
std::string m_name;
std::chrono::time_point<clock_t> m_beg;
double elapsed() const
{
return std::chrono::duration_cast<second_t>(clock_t::now()
- m_beg).count();
}
public:
Timer() : m_beg(clock_t::now()) { }
Timer(std::string name) : m_name(name), m_beg(clock_t::now()) { }
void start(std::string name) {
m_name = name;
m_beg = clock_t::now();
}
void print() const {
std::cout << m_name << ":\t" << elapsed() * 1000 << " ms" << '\n';
}
};
const std::string vowels = "аеёиоуыэюяАЕЁИОУЫЭЮЯ";
size_t ForFor(std::string& ww)
{
size_t count = 0;
Timer t1("for for");
for(const auto& ch : ww)
{
for (const auto& vow : vowels)
{
if (ch == vow)
{
++count;
break;
}
}
}
t1.print();
return count;
}
size_t CountIfFind(std::string& ww)
{
Timer t("count_if/find");
size_t count = std::count_if(ww.begin(), ww.end(), [ & ](char c) {return vowels.find(c) != std::string::npos; });
t.print();
return count;
}
size_t CountIfFor(std::string& ww)
{
Timer t("count_if/for");
size_t count = std::count_if(ww.begin(), ww.end(), [&](const char& c1)
{
for (const auto& ch : vowels)
{
if (c1 == ch)
{
return true;
}
}
return false;
});
t.print();
return count;
}
size_t ForFind(std::string& ww)
{
char c{};
size_t count = 0;
Timer t("for/find");
for (const auto& ch :ww)
{
if (vowels.find(ch) != std::string::npos)
{
++count;
}
}
t.print();
return count;
}
int main()
{SetConsoleCP(1251);
SetConsoleOutputCP(1251);
std::ifstream file("Толстой Лев. Война и мир. Книга 1 - royallib.ru.txt");
file.seekg(0, std::ios::end);
size_t size = file.tellg();
file.seekg(0);
std::string s(size, ' ');
file.read(&s[0], size);
std::cout << CountIfFind(s) << std::endl;
std::cout << ForFor(s) << std::endl;
std::cout << ForFind(s) << std::endl;
std::cout << CountIfFor(s) << std:: endl;
}
I am using VS code for coding in C++. The problem arises when I try to debug a code and set a breakpoint. The local variables pane doesn't show any variables at all. Sometimes it does show some variables but not all of them.
Also when I try to close the debugger and click on the stop button, it does not stop. It requires me to click on it multiple times, which I think means, that multiple debuggers are opened or something like that.
To reproduce this problem, save this text as input_static.txt.
T1 1 2 5
T2 2 4
T3 2 3
T4 1 2 4
T5 1 3
T6 2 3
T7 1 3
T8 1 2 3 5
T9 1 2 3
And debug the following code by setting a breakpoint at line number 201.
#include <bits/stdc++.h>
using namespace std;
ifstream fin;
ofstream fout;
typedef struct fptnode
{
int item, count;
fptnode *next;
map<int, fptnode *> children;
fptnode *parent;
fptnode(int item, int count, fptnode *parent)
{
this->item = item;
this->count = count;
this->parent = parent;
}
} * FPTPTR;
map<int, int> frequency;
bool isMoreFrequent(int a, int b)
{
if (frequency[a] == frequency[b])
return a < b;
return frequency[a] > frequency[b];
}
class FPTREE
{
public:
FPTPTR root;
map<int, list<FPTPTR>> headers;
// map<int, int> frequency;
FPTREE()
{
this->root = new fptnode(-1, 0, NULL);
}
// class isMoreFrequent
// {
// public:
// FPTREE *T;
// isMoreFrequent(FPTREE *T)
// {
// this->T = T;
// }
// bool operator()(int item1, int item2)
// {
// return T->frequency[item1] > T->frequency[item2];
// }
// };
FPTPTR getNewNode(int item, int count, fptnode *parent)
{
FPTPTR T = new fptnode(item, count, parent);
this->headers[item].push_back(T);
return T;
}
void add(vector<int> &transaction)
{
stack<int> S;
std::sort(transaction.begin(), transaction.end(), isMoreFrequent);
for (int i = transaction.size() - 1; i >= 0; i--)
{
S.push(transaction[i]);
}
insert(root, S);
}
int insert(FPTPTR T, stack<int> &S)
{
T->count++;
if (S.empty())
return 0;
int top = S.top();
S.pop();
if (T->children[top] == NULL)
{
T->children[top] = getNewNode(top, 0, T);
}
insert(T->children[top], S);
return 0;
}
void printPreOrder(ofstream &fout)
{
printPreOrder(fout, this->root);
}
void printPreOrder(ofstream &fout, FPTPTR T)
{
if (T)
{
fout << "[" << T->item << ", " << T->count << "]" << ' ';
for (auto p : T->children)
{
printPreOrder(fout, p.second);
}
}
}
void printTree(ofstream &fout)
{
printTree(fout, this->root);
}
void printTree(ofstream &fout, FPTPTR T, int level = 0)
{
if (T)
{
for (int i = 0; i < level; i++)
fout << "\t";
fout << "[" << T->item << ", " << T->count << "]" << endl;
for (auto p : T->children)
{
printTree(fout, p.second, level + 1);
}
}
}
void generatePath(FPTPTR node, vector<int> &path)
{
if (node && node->item >= 0)
{
path.push_back(node->item);
generatePath(node->parent, path);
}
}
FPTREE newTree(int item)
{
list<FPTPTR> &nodes = this->headers[item];
vector<int> patternBase;
FPTREE f;
for (auto node : nodes)
{
patternBase.clear();
generatePath(node->parent, patternBase);
for (int j = 0; j < node->count; ++j)
f.add(patternBase);
}
return f;
}
int clear()
{
return this->clear(this->root);
}
int clear(FPTPTR T)
{
for (auto p : T->children)
{
clear(p.second);
}
return 0;
}
bool isEmpty()
{
// return this->root->count == 0;
return this->root->children.empty();
}
} F;
ofstream tempout;
map<set<int>, int> mine(FPTREE f, int r = -1)
{
map<set<int>, int> M;
if (!f.isEmpty())
{
// if (f.root->children.empty())
// M[{}] += f.root->count;
tempout << "\nOn removing " << r << ":\n";
f.printTree(tempout);
for (auto p : frequency)
{
FPTREE subF = f.newTree(p.first);
map<set<int>, int> m = mine(subF, p.first);
for (auto q : m)
{
auto itemset = q.first;
itemset.insert(p.first);
M[itemset] += q.second;
}
subF.clear();
}
return M;
}
// tempout << "\nTerminated.\n";
return {};
}
int main(int argc, char const *argv[])
{
fin.open("input_static.txt");
fout.open("output_static.txt");
tempout.open("temp");
string str, s;
while (fin >> s)
{
if (s.front() != 'T')
{
frequency[stoi(s)]++;
}
}
vector<int> transaction;
stringstream st;
fin.clear();
fin.seekg(0);
while (std::getline(fin, str))
{
st.clear();
st.str(str);
transaction.clear();
while (st >> s)
{
if (s.front() != 'T')
{
transaction.push_back(stoi(s));
}
}
F.add(transaction);
}
fout << "Preorder:\n";
F.printPreOrder(fout);
fout << endl
<< endl;
fout << "Tree in directory form:\n";
F.printTree(fout);
// printPrefixes(5);
map<set<int>, int> frequentItemsets = mine(F);
fout << endl;
for (auto p : frequentItemsets)
{
fout << "Frequency=" << p.second << "\t";
for (int item : p.first)
{
fout << item << ' ';
}
fout << endl;
}
// for (int i = 1; i <= 5; ++i)
// {
// fout << i << ":\n";
// FPTREE f = F.newTree(i);
// f.printTree();
// }
// F.newTree(1).newTree(2).printTree(fout);
return 0;
}
If it helps this is a program to generate and mine an FP-tree to find frequent itemsets in a transactional database.
I am creating an minimax player for a game called Specker in c++.
The rules are simple:
There are p players (0 to p - 1) and n heaps (0 to n - 1)
Starting with player 0 each player takes k > 0 coins from a heap x and places m coins (0 <= m < k) on heap y
The winning player is the one which plays last when all coins from all heaps are removed
So I have created the game and some player classes (GreedyPlayer, SpartanPlayer etc.) but they all are a little bit predictable on what they will do. They aren't clever.
so i am creating a player who plays according to minimax (pt18a038)code compiles fine but the program stops responding on execution.
the clever player class:
class pt18a038 : public Player {
private:
string player_type;
public:
pt18a038(const string &n) : Player(n) {
player_type = "Asder aka theRunner";
}
virtual const string &getType() const override {
return player_type;
}
virtual Move play(const State &s) override {
int source_heap = 0;
int target_heap = 0;
int source_coins = 0;
int target_coins = 0;
int sum = 0;
for (source_heap = 0; source_heap < s.getHeaps(); source_heap++) {
for (source_coins = 1; source_coins <= s.getCoins(source_heap); source_coins++) {
for (target_heap = 0; target_heap < s.getHeaps(); target_heap++) {
for (target_coins = 0; target_coins <= source_coins; target_coins++) {
Move m(source_heap, source_coins, target_heap, target_coins);
sum = minimax(s, 3, 0, m);
cout << "Play:" << source_heap << "," << source_coins << "," << target_heap << ","
<< target_coins << ":" << sum << endl;
}
}
}
}
cout << sum << endl;
// ///////////// for debbuging only until minimax is working...
source_heap = 0;
source_coins = 0;
for (int i = 0; i < s.getHeaps(); i++) {
if (s.getCoins(i) > source_coins) {
source_heap = i;
source_coins = s.getCoins(i);
}
}
Move SpartanObject(source_heap, 1, 0, 0);
return SpartanObject;
// /////////////
}
static int minimax(State s, const int &players, int depth, const Move move) {
if (s.winning()) {
cout << "game end!" << endl;
return 1000;
if (depth % players == 0) return 1000; //Maximazing player
else return -1000; //Minimazing player
}
if (depth > 4) {
//cout<<"optimazing"<<endl;
return 0;
}
//cout << s << endl;
s.next(move);
int source_heap = 0;
int target_heap = 0;
int source_coins = 0;
int target_coins = 0;
int max = -100000;
int min = 100000;
int result;
for (source_heap = 0; source_heap < s.getHeaps(); source_heap++) {
for (source_coins = 1; source_coins <= s.getCoins(source_heap); source_coins++) {
for (target_heap = 0; target_heap < s.getHeaps(); target_heap++) {
for (target_coins = 0; target_coins <= source_coins; target_coins++) {
//cout << "Move:" << source_heap << "," << source_coins << "," << target_heap << ","<< target_coins << endl;
Move m(source_heap, source_coins, target_heap, target_coins);
result = minimax(s, players, depth + 1, m);
if (depth % players == 0) {
max = result ? (result > max) : result;
} else {
min = result ? (result < min) : result;
}
}
}
}
}
return max ? (depth % players == 0) : min;
}
};
Here is my code for the rest of the game(it's tested and works fine)
#include <iostream>
#include <stdexcept>
using namespace std;
class Move {
private:
int source_heap, source_coins, target_heap, target_coins;
public:
Move(int sh, int sc, int th, int tc) {
source_heap = sh;
source_coins = sc;
target_heap = th;
target_coins = tc;
}
int getSource() const {
return source_heap;
}
int getSourceCoins() const {
return source_coins;
}
int getTarget() const {
return target_heap;
}
int getTargetCoins() const {
return target_coins;
}
// Let's do some operator overloading
friend ostream &operator<<(ostream &out, const Move &move) {
if (move.getTargetCoins()) {
out << "takes " << move.getSourceCoins() << " coins from heap "
<< move.getSource() << " and puts " << move.getTargetCoins()
<< " coins to heap " << move.getTarget();
} else {
out << "takes " << move.getSourceCoins() << " coins from heap "
<< move.getSource() << " and puts nothing";
}
}
};
class State {
// State with h heaps, where the i-th heap starts with c[i] coins.
private:
int heaps, *heap_coins;
public:
State(int h, const int c[]) {
heaps = h;
heap_coins = new int[heaps];
for (int i = 0; i < heaps; i++)
heap_coins[i] = c[i];
}
~State() {
delete[] heap_coins;
return;
}
int getCoins(int h) const throw(logic_error) {
if (h < 0 || h > heaps) {
throw logic_error(
"Invalid heap number, enter a number between 1 and heaps!");
return 1;
} else {
return heap_coins[h];
}
}
void next(const Move &move) throw(logic_error) {
if ((move.getSource() < 0) || (move.getSource() > heaps) ||
(move.getTarget() < 0) || (move.getTarget() > heaps)) {
throw logic_error("Invalid Heap!");
return;
} else if (
(move.getSourceCoins() < 1) || (move.getTargetCoins() < 0) ||
(move.getSourceCoins() <= move.getTargetCoins()) ||
(move.getSourceCoins() > getCoins(move.getSource()))) {
throw logic_error("Invalid Coin number!");
} else {
heap_coins[move.getSource()] -= move.getSourceCoins();
heap_coins[move.getTarget()] += move.getTargetCoins();
}
}
bool winning() const {
int s = 0;
for (int i = 0; i < heaps; i++)
s += getCoins(i);
return not s; // yeah i know how booleans work :P
}
int getHeaps() const {
return heaps;
}
friend ostream &operator<<(ostream &out, const State &state) {
for (int i = 0; i < state.getHeaps(); i++) {
out << state.heap_coins[i];
if (i != state.getHeaps() - 1)
out << ", ";
}
return out;
}
};
class Player {
public:
Player(const string &n);
virtual ~Player();
virtual const string &getType() const = 0;
virtual Move play(const State &s) = 0;
friend ostream &operator<<(ostream &out, const Player &player);
protected:
string player_name;
};
class GreedyPlayer : public Player {
private:
string player_type;
public:
GreedyPlayer(const string &n) : Player(n) {
player_type = "Greedy";
}
virtual const string &getType() const override {
return player_type;
}
virtual Move play(const State &s) override {
int source_heap = 0;
int source_coins = 0;
for (int i = 0; i < s.getHeaps(); i++) {
if (s.getCoins(i) > source_coins) {
source_heap = i;
source_coins = s.getCoins(i);
}
}
Move GreedyObject(source_heap, source_coins, 0, 0);
return GreedyObject;
}
};
class SpartanPlayer : public Player {
public:
SpartanPlayer(const string &n) : Player(n) {
player_type = "Spartan";
}
virtual const string &getType() const override {
return player_type;
}
virtual Move play(const State &s) override {
int source_heap = 0;
int source_coins = 0;
for (int i = 0; i < s.getHeaps(); i++) {
if (s.getCoins(i) > source_coins) {
source_heap = i;
source_coins = s.getCoins(i);
}
}
Move SpartanObject(source_heap, 1, 0, 0);
return SpartanObject;
}
private:
string player_type;
};
class SneakyPlayer : public Player {
public:
SneakyPlayer(const string &n) : Player(n) {
player_type = "Sneaky";
}
virtual const string &getType() const override {
return player_type;
}
virtual Move play(const State &s) override {
int j = 0;
while (s.getCoins(j) == 0) {
j++;
}
int source_heap = j;
int source_coins = s.getCoins(j);
for (int i = j + 1; i < s.getHeaps(); i++) {
if ((s.getCoins(i) < source_coins) && (s.getCoins(i) > 0)) {
source_heap = i;
source_coins = s.getCoins(i);
}
}
Move SneakyObject(source_heap, source_coins, 0, 0);
return SneakyObject;
}
private:
string player_type;
};
class RighteousPlayer : public Player {
public:
RighteousPlayer(const string &n) : Player(n) {
player_type = "Righteous";
}
virtual const string &getType() const override {
return player_type;
}
virtual Move play(const State &s) override {
int target_heap = 0;
int source_heap = 0;
int source_coins = s.getCoins(0);
int target_coins = source_coins;
for (int i = 1; i < s.getHeaps(); i++) {
if (s.getCoins(i) > source_coins) {
source_heap = i;
source_coins = s.getCoins(i);
} else if (s.getCoins(i) < target_coins) {
target_heap = i;
target_coins = s.getCoins(i);
}
}
source_coins -= source_coins / 2;
Move RighteousObject(
source_heap, source_coins, target_heap, source_coins - 1);
return RighteousObject;
}
private:
string player_type;
};
Player::Player(const string &n) {
player_name = n;
}
Player::~Player() {
player_name.clear();
}
ostream &operator<<(ostream &out, const Player &player) {
out << player.getType() << " player " << player.player_name;
return out;
}
class Game {
private:
int game_heaps, game_players, current_heap, current_player;
int *heap_coins;
Player **players_list;
public:
Game(int heaps, int players) {
heap_coins= new int [heaps];
game_heaps = heaps;
game_players = players;
current_heap = 0;
current_player = 0;
players_list = new Player*[players];
}
~Game() {
delete[] heap_coins;
delete[] players_list;
}
void addHeap(int coins) throw(logic_error) {
if (current_heap > game_heaps)
throw logic_error("All heaps are full with coins!");
else if (coins < 0)
throw logic_error("Coins must be a positive number!");
else {
heap_coins[current_heap++] = coins;
}
}
void addPlayer(Player *player) throw(logic_error) {
if (current_player > game_players)
throw logic_error("All players are added!");
else {
players_list[current_player++] = player;
}
}
void play(ostream &out) throw(logic_error) {
if ((current_player != game_players) && (current_heap != game_heaps)) {
throw logic_error("Have you added all heaps and players?");
} else {
int i = 0;
State currentState(game_heaps, heap_coins);
while (!currentState.winning()) {
out << "State: " << currentState << endl;
out << *players_list[i % game_players] << " "
<< players_list[i % game_players]->play(currentState) << endl;
currentState.next(
players_list[i % game_players]->play(currentState));
i++;
}
out << "State: " << currentState << endl;
i--;
out << *players_list[i % game_players] << " wins" << endl;
}
}
};
int main() {
Game specker(6, 5);
specker.addHeap(10);
specker.addHeap(20);
specker.addHeap(17);
specker.addHeap(17);
specker.addHeap(17);
specker.addHeap(17);
specker.addPlayer(new GreedyPlayer("Alan"));
specker.addPlayer(new SneakyPlayer("Tom"));
specker.addPlayer(new SpartanPlayer("Mary"));
specker.addPlayer(new RighteousPlayer("Robin"));
specker.addPlayer(new pt18a038("Stavros"));
specker.play(cout);
}
Updated
I see a couple of issues in your minimax program, some are serious in nature :
1) Use Alpha Beta pruning to reduce the size of the search tree.
2) There is no proper boundary condition (if depth >5 return score or something) in the minimax recursive call ( see my code snippet for details), the CPU may hang while calling.
3)Your leaf node evaluation is weak, so the evaluated moves , in spite of using minimax algorithm, is not likely to be intelligent ones.
4)To increase the search speed, you may use multi-threading only at the top level branch.
5) If a leaf node gives a winning move while maximizing, you may skip further evaluation by returning a high score.
6) Once your code is functional, refer it at code-review with 'ai' tag , rather than at SO, for more detailed analysis.
int EvaluateLeafNode(State s, const int &players)
{
//TODO analyze here
return score;
}
int minimax(State s, const int &players, int depth , const Move move, int alpha, int beta)
{
if( depth >= 5) return EvaluateLeafNode(s,players); // this was missing in your code
//don't analyze here
//rest of minimax recursive code
}
I'm new to C++. I'm trying to make inverted index but I can't understand the cord. I want to count the frequency of the word. Can you explain this code and how to count the frequency of the word? Please help me to solve this problem.
class node{
public:
node() {
clear();
}
node(char z) {
clear();
}
~node() {
for (int x = 0; x < MAX_NODES; x++) {
if (next[x]) {
delete next[x];
}
}
}
void clear() {
for (int x = 0; x < MAX_NODES; x++){
next[x] = 0;
isWord = false;
}
}
bool isWord;
int count;//frq
std::vector<std::string> files;
node* next[MAX_NODES];
map<string, int> counts;
};
class index {
public:
void add(std::string s, std::string fileName) {
std::transform(s.begin(), s.end(), s.begin(), tolower);
std::string h;
int freq=0;
for (std::string::iterator i = s.begin(); i != s.end(); i++) {
if (*i == 32) {
pushFileName(addWord(h), fileName);
h.clear();
continue;
}
h.append(1, *i);
}
if (h.length()){
pushFileName(addWord(h), fileName);
}
}
void findWord(std::string s, map<string, int> counts) {
std::vector<std::string> v = find(s);
if (!v.size()) {
std::cout <<"'"<< s + "' is not found!\n";
return;
}
std::cout << "'" << s << "' is found in:\n";
for (std::vector<std::string>::iterator i = v.begin(); i != v.end(); i++) {
std::cout << *i << "\n";
}
std::cout << "frequency is : ";
}
private:
void pushFileName(node* n, std::string fn) {
std::vector<std::string>::iterator i = std::find(n->files.begin(), n->files.end(), fn);
if (i == n->files.end()){
n->files.push_back(fn);
n->count;
}
}
const std::vector<std::string>& find(std::string s) {
size_t idx;
std::transform(s.begin(), s.end(), s.begin(), tolower);
node* rt = &root;
for (std::string::iterator i = s.begin(); i != s.end(); i++) {
idx = _CHARS.find(*i);
if (idx < MAX_NODES) {
if (!rt->next[idx]){
return std::vector<std::string>();
}
rt = rt->next[idx];
}
}
if (rt->isWord) return rt->files;
return std::vector<std::string>();
}
node* addWord(std::string s) {
size_t idx;
node *rt = &root, *n;
for (std::string::iterator i = s.begin(); i != s.end(); i++) {
idx = _CHARS.find(*i);
if (idx < MAX_NODES) {
n = rt->next[idx];
if (n){
rt = n;
continue;
}
n = new node(*i);
rt->next[idx] = n;
rt = n;
}
}
rt->isWord = true;
rt->count++;
return rt;
}
node root;
};
class index {
public:
void add(std::string s, std::string fileName) {
std::transform(s.begin(), s.end(), s.begin(), tolower);
std::string h;
int freq=0;
for (std::string::iterator i = s.begin(); i != s.end(); i++) {
if (*i == 32) {
pushFileName(addWord(h), fileName);
h.clear();
continue;
}
h.append(1, *i);
}
if (h.length()){
pushFileName(addWord(h), fileName);
}
}
void findWord(std::string s, map<string, int> mFilesFreq) {
std::vector<std::string> v = find(s);
if (!v.size()) {
std::cout <<"'"<< s + "' is not found!\n";
return;
}
std::cout << "'" << s << "' is found in:\n";
for (std::vector<std::string>::iterator i = v.begin(); i != v.end(); i++) {
std::cout << *i << "\n";
}
std::cout << "frequency is : ";
}
If you are counting the number of times add was called for a given word, you probably want to replace rt->isWord = true; with rt->count++; and in your struct node replace bool isWord with int count.
I have read the question What's the performance penalty of weak_ptr? but my own tests show different results.
I'm making delegates with smart pointers. The simple code below shows reproduces the performance issues with weak_ptr. Can anybody tell me why?
#include <chrono>
#include <functional>
#include <iostream>
#include <memory>
#include <stdint.h>
#include <string>
#include <utility>
struct Foo
{
Foo() : counter(0) { incrStep = 1;}
void bar()
{
counter += incrStep;
}
virtual ~Foo()
{
std::cout << "End " << counter << std::endl;
}
private:
uint64_t counter;
uint64_t incrStep;
};
void pf(const std::string &md, const std::function<void()> &g)
{
const auto st = std::chrono::high_resolution_clock::now();
g();
const auto ft = std::chrono::high_resolution_clock::now();
const auto del = std::chrono::duration_cast<std::chrono::milliseconds>(ft - st);
std::cout << md << " \t: \t" << del.count() << std::endl;
}
And the test:
int main(int , char** )
{
volatile size_t l = 1000000000ULL;
size_t maxCounter = l;
auto a = std::make_shared<Foo>();
std::weak_ptr<Foo> wp = a;
pf("call via raw ptr ", [=](){
for (size_t i = 0; i < maxCounter; ++i)
{
auto p = a.get();
if (p)
{
p->bar();
}
}
});
pf("call via shared_ptr ", [=](){
for (size_t i = 0; i < maxCounter; ++i)
{
if (a)
{
a->bar();
}
}
});
pf("call via weak_ptr ", [=](){
std::shared_ptr<Foo> p;
for (size_t i = 0; i < maxCounter; ++i)
{
p = wp.lock();
if (p)
{
p->bar();
}
}
});
pf("call via shared_ptr copy", [=](){
volatile std::shared_ptr<Foo> p1 = a;
std::shared_ptr<Foo> p;
for (size_t i = 0; i < maxCounter; ++i)
{
p = const_cast<std::shared_ptr<Foo>& >(p1);
if (p)
{
p->bar();
}
}
});
pf("call via mem_fn ", [=](){
auto fff = std::mem_fn(&Foo::bar);
for (size_t i = 0; i < maxCounter; ++i)
{
fff(a.get());
}
});
return 0;
}
Results:
$ ./test
call via raw ptr : 369
call via shared_ptr : 302
call via weak_ptr : 22663
call via shared_ptr copy : 2171
call via mem_fn : 2124
End 5000000000
As you can see, weak_ptr is 10 times slower than shared_ptr with copying and std::mem_fn and 60 times slower than using raw ptr or shared_ptr.get()
In trying to reproduce your test I realised that the optimizer might be eliminating more than it should. What I did was to utilize random numbers to defeat over-optimization and these results seem realistic with std::weak_ptr being nearly three times slower than the std::shared_ptr or its raw pointer.
I calculate a checksum in each test to ensure they are all doing the same work:
#include <chrono>
#include <memory>
#include <random>
#include <vector>
#include <iomanip>
#include <iostream>
#define OUT(m) do{std::cout << m << '\n';}while(0)
class Timer
{
using clock = std::chrono::steady_clock;
using microseconds = std::chrono::microseconds;
clock::time_point tsb;
clock::time_point tse;
public:
void start() { tsb = clock::now(); }
void stop() { tse = clock::now(); }
void clear() { tsb = tse; }
friend std::ostream& operator<<(std::ostream& o, const Timer& timer)
{
return o << timer.secs();
}
// return time difference in seconds
double secs() const
{
if(tse <= tsb)
return 0.0;
auto d = std::chrono::duration_cast<microseconds>(tse - tsb);
return double(d.count()) / 1000000.0;
}
};
constexpr auto N = 100000000U;
int main()
{
std::mt19937 rnd{std::random_device{}()};
std::uniform_int_distribution<int> pick{0, 100};
std::vector<int> random_ints;
for(auto i = 0U; i < 1024; ++i)
random_ints.push_back(pick(rnd));
std::shared_ptr<int> sptr = std::make_shared<int>(std::rand() % 100);
int* rptr = sptr.get();
std::weak_ptr<int> wptr = sptr;
Timer timer;
unsigned sum = 0;
sum = 0;
timer.start();
for(auto i = 0U; i < N; ++i)
{
sum += random_ints[i % random_ints.size()] * *sptr;
}
timer.stop();
OUT("sptr: " << sum << " " << timer);
sum = 0;
timer.start();
for(auto i = 0U; i < N; ++i)
{
sum += random_ints[i % random_ints.size()] * *rptr;
}
timer.stop();
OUT("rptr: " << sum << " " << timer);
sum = 0;
timer.start();
for(auto i = 0U; i < N; ++i)
{
sum += random_ints[i % random_ints.size()] * *wptr.lock();
}
timer.stop();
OUT("wptr: " << sum << " " << timer);
}
Compiler flags:
g++ -std=c++14 -O3 -g0 -D NDEBUG -o bin/timecpp src/timecpp.cpp
Example Output:
sptr: 1367265700 1.26869 // shared pointer
rptr: 1367265700 1.26435 // raw pointer
wptr: 1367265700 2.99008 // weak pointer