Following the McNellis's presentation for coroutines(Introduction to C Coroutines), I try to compile the example of the simple coroutine, which actually is a simple counter.
However when the resume is called ,assertion is fired.
Specifically
_LIBCPP_ASSERT(!done(),
"resume() has undefined behaviour when the coroutine is done");
I have not much experience with coroutines and I cannot find out what goes wrong.
The code is below
#include <iostream>
#include <coroutine>
using namespace std;
//using namespace experimental;
struct resumable_thing
{
struct promise_type
{
int const* _current;
promise_type & get_return_object() noexcept
{
return *this;
}
auto initial_suspend() { return suspend_always{}; }
auto final_suspend() { return suspend_always{}; }
auto yield_value(int const& value) {
_current = &value;
return suspend_always{};
}
void unhandled_exception()
{
auto ex = std::current_exception();
std::rethrow_exception(ex);
//// MSVC bug? should be possible to rethrow with "throw;"
//// rethrow exception immediately
// throw;
}
void return_void() noexcept
{
}
};
// using coroutine_handle = coroutine_handle<promise_type>;
resumable_thing() = default;
resumable_thing(resumable_thing const & ) = delete;
resumable_thing & operator = (resumable_thing const & ) =delete;
resumable_thing(promise_type && promise)
: _coroutine(coroutine_handle<promise_type>::from_promise(promise)) {}
resumable_thing(resumable_thing&& other) : _coroutine(other._coroutine)
{
other._coroutine = nullptr;
}
resumable_thing & operator = (resumable_thing const && other)
{
_coroutine = other._coroutine;
_coroutine = nullptr;
return *this;
}
explicit resumable_thing(coroutine_handle<promise_type> coroutine)
:_coroutine(coroutine)
{
}
~resumable_thing()
{
if(_coroutine)
{
_coroutine.destroy();
}
}
void resume()
{
std::cout << "coroutines resume" << std::endl;
_coroutine.resume();
}
coroutine_handle<promise_type> _coroutine = nullptr;
};
resumable_thing counter()
{
cout << "counter: called\n";
for(int i = 0 ; ++i;)
{
co_await suspend_always{};
cout << "counter: resumed (#" << i << ")\n";
}
}
int main(int argc, const char * argv[]) {
// insert code here...
cout << "main: calling counter\n";
resumable_thing the_counter = counter();
cout << "main: resuming counter\n";
the_counter.resume();//assertion is fired
cout << "main:done" << std::endl;
return 0;
}
Please find the code here
promise_type::get_return_object() shall return user-defined coroutine result type resumable_thing, instead of promise_type& itself.
struct resumable_thing
{
struct promise_type
{
resumable_thing get_return_object() noexcept
{
return {*this};
}
// ...
};
resumable_thing(promise_type & promise)
: _coroutine(coroutine_handle<promise_type>::from_promise(promise)) {}
// ...
};
And resumable_thing's move assignment operator resets this->_coroutine unintentionally.
// FIXED: resumable_thing const && -> resumable_thing &&
resumable_thing & operator = (resumable_thing && other)
{
_coroutine = other._coroutine;
// FIXED: _coroutine -> other._coroutine
other._coroutine = nullptr;
return *this;
}
Related
We have been restricted us to not use a loop in a program as a programming challenge.
Restrictions:
You can not use while, for, goto and recursion.
The restrictions are pretty daunting. I couldn't really think of any proper solution.
So I opted for this one which is achieved by modifying the return address.
Could this be any better?
#include <unistd.h>
#include <sys/mman.h>
#include <iostream>
#include <cstring>
void the__(){}
void magic__(){}
void loop__(){}
void function__(){}
void here__(){}
template <typename T>
struct for_
{
bool started = false;
void* fix = nullptr;
void(*body)(T&) = nullptr;
for_(void(*body)(T&))
: body(body)
{
auto do_for__ = uintptr_t(do_for_);
uint64_t magic[] = {5243466812662057800, 6135086863767628931ull, 10416984888688609608ull, 144};
mprotect((void*)(do_for__-do_for__%4096), 4096, 7);
std::memcpy((void*)(do_for__+135), magic, 25);
}
static void do_for_(T& ctx)
{
void** p = (void**)((char*)&p+16);
if (!ctx.started)
{
if (!ctx) return;
ctx.started = true;
ctx.fix = *p;
*p = (void*)do_for_;
}
ctx.body(ctx);
ctx.next();
if (ctx)
{
the__();
magic__();
loop__();
function__();
here__();
}
else
{
*p = ctx.fix;
}
}
};
struct For0ToN : for_<For0ToN>
{
For0ToN(int N, void(*f)(For0ToN&))
: for_<For0ToN>(f)
, N(N)
{
do_for_(*this);
}
operator bool() {return i < N;}
operator int() {return i;}
void next() {i++;}
int count() {return i;}
int i = 0, N = 0;
};
int main()
{
For0ToN(10, +[](For0ToN& i)
{
std::cout << int(i) << ": ";
For0ToN(i.count(), +[](For0ToN& i)
{
std::cout << int(i) << ". ";
});
std::cout << "\n";
});
std::cout << "done\n";
return 0;
}
The code is demonstrated here: https://coliru.stacked-crooked.com/a/3dd77ade501ac748
You could use longjmp. Here's an example from cppreference:
#include <csetjmp>
#include <iostream>
std::jmp_buf jump_buffer;
[[noreturn]] void a(int count)
{
std::cout << "a(" << count << ") called\n";
std::longjmp(jump_buffer, count+1); // setjmp() will return count+1
}
int main() {
// loop from 0-9
volatile int count = 0; // local variables must be volatile for setjmp
if (setjmp(jump_buffer) != 10) {
a(count++); // This will cause setjmp() to exit
}
}
Question is unclear but 1 alternative of the loop is std::transform()
Template metaprogramming is common way of avoiding writing explicit loop in code. This work gets done by compiler. Check this for examples of factorial and bubble sort implementation without writing explicit loops. You can check this stack overflow post as well.
Does it count if I hide recursion into function objects and create a finite state machine?
struct state
{
size_t current_column;
size_t current_row;
size_t max_column;
size_t max_row;
};
typedef function<void(state&)> action_t;
struct do_item
{
do_item(ostream& ss, action_t* move_next)
: ss_(ss), move_next_(move_next) {}
void operator()(state& s)
{
if (s.current_row == s.max_row)
{
ss_ << "done";
return;
}
if (0 == s.current_column)
{
ss_ << s.current_row << ':';
}
if (s.max_column == s.current_column)
{
ss_ << '\n';
s.current_column = 0;
++s.current_row;
s.max_column = s.current_row;
}
else
{
ss_ << ' ' << s.current_column << '.';
++s.current_column;
}
(*move_next_)(s);
}
ostream& ss_;
action_t* move_next_;
};
static string no_loops_challenge(size_t n)
{
stringstream ss;
state s = {0, 0, 0, n};
action_t move_next;
do_item action(ss, &move_next);
move_next = action;
action(s);
return ss.str();
}
Here's a solution using range-v3 that should satisfy all the constraints:
namespace rv = ranges::views;
ranges::for_each(rv::iota(0, 10), [](int i) {
std::cout << i << ": ";
ranges::copy(rv::iota(0, i),
ranges::ostream_iterator<int>(std::cout, ". "));
std::cout << "\n";
});
Here's a demo.
I have the below program of an execution class which populates a map shown below
map<string,map<string,vector<StructAbsTypeObject>>>
Here I am making shared objects and assigning them which are valid during first check, but on second check shared_ptr returns null. I need to know the reason why. The code seems fine but don't know where is it going wrong.
//Code begins
#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <memory>
using namespace std;
class Test {
public:
Test(int i):t(i) {
}
private:
int t;
};
class ConcTypeObject {
public:
ConcTypeObject() {
}
ConcTypeObject(const ConcTypeObject& other) {
m_ptr_Test = other.m_ptr_Test;
}
ConcTypeObject& operator=(const ConcTypeObject& other) {
m_ptr_Test = other.m_ptr_Test;
}
void setTest(shared_ptr<Test> ptr) {
cout << "setTest" << endl;
m_ptr_Test = ptr;
}
shared_ptr<Test> getTest() {
return m_ptr_Test;
}
bool isValid() {
if(m_ptr_Test) {
return true;
} else {
return false;
}
}
private:
shared_ptr<Test> m_ptr_Test;
};
class AbsTypeObject {
public:
explicit AbsTypeObject(const string str) {
m_str = str;
}
AbsTypeObject(const AbsTypeObject& other) {
m_str = other.m_str;
m_ptr_ConcTypeObject = other.m_ptr_ConcTypeObject;
}
AbsTypeObject& operator=(const AbsTypeObject& other) {
m_str = other.m_str;
m_ptr_ConcTypeObject = other.m_ptr_ConcTypeObject;
}
bool operator==(const AbsTypeObject& other) {
if(m_str == other.m_str)
return true;
else
return false;
}
void setConcTypeObject(shared_ptr<ConcTypeObject> ptr) {
m_ptr_ConcTypeObject = ptr;
}
shared_ptr<ConcTypeObject> getConcTypeObject() {
return m_ptr_ConcTypeObject;
}
bool isValid() {
if(m_ptr_ConcTypeObject) {
cout << "AbsTypeObject 1 " << endl;
return m_ptr_ConcTypeObject->isValid();
} else {
cout << "AbsTypeObject 2 " << endl;
return false;
}
}
private:
string m_str;
shared_ptr<ConcTypeObject> m_ptr_ConcTypeObject;
};
class StructAbsTypeObject {
public:
StructAbsTypeObject(const string str):m_AbsTypeObject(str) {
}
void SetAbsTypeObject(AbsTypeObject& id) {
m_AbsTypeObject = id;
}
AbsTypeObject& GetAbsTypeObject() {
return m_AbsTypeObject;
}
private:
AbsTypeObject m_AbsTypeObject;
};
class Executor {
public:
static Executor m_Executor;
static Executor& get() {
return m_Executor;
}
Executor() {
StructAbsTypeObject sid(std::string("ABCD"));
vector<StructAbsTypeObject> a_vecstid;
a_vecstid.push_back(sid);
m_executormap["ExecutorInterface"]["ExecutorName"] = a_vecstid;
}
void check() {
for(auto outermap : m_executormap) {
for(auto innermap : outermap.second) {
for(auto vec_element: innermap.second) {
if(vec_element.GetAbsTypeObject().isValid()) {
cout << "PTR VALID" << endl;
} else {
cout << "PTR NOT Valid" << endl;
}
}
}
}
}
void fillAbsTypeObject(AbsTypeObject &id) {
shared_ptr<Test> ptr_test = make_shared<Test>(20);
shared_ptr<ConcTypeObject> ptr_ConcTypeObject = make_shared<ConcTypeObject>();
id.setConcTypeObject(ptr_ConcTypeObject);
id.getConcTypeObject()->setTest(ptr_test);
}
void Init(AbsTypeObject id) {
for(auto outermap : m_executormap) {
for(auto innermap : outermap.second) {
for(auto vec_element: innermap.second) {
if(vec_element.GetAbsTypeObject() == id) {
cout << "Id Equal" << endl;
fillAbsTypeObject(id);
vec_element.SetAbsTypeObject(id);
if(vec_element.GetAbsTypeObject().isValid()) {
cout << "PTR VALID" << endl;
} else {
cout << "PTR NOT Valid" << endl;
}
}
}
}
check();
}
}
private:
using executormap = map<string,map<string,vector<StructAbsTypeObject>>>;
executormap m_executormap;
};
Executor Executor::m_Executor;
int main()
{
AbsTypeObject id(std::string("ABCD"));
Executor::get().Init(id);
}
//Code Ends
The above code is completely compilable and Runnable. Currently I am getting the following output
//Output Begins
Id Equal
setTest
AbsTypeObject 1
PTR VALID
AbsTypeObject 2
PTR NOT Valid
//Output Ends
The PTR NOT VALID is output when check function is executed. Expecting output is
PTR VALID in both cases.
Please let me know what is going wrong in the above code. I did try few things but did not work. If it does not work, what is the reason and what is the correct way to make it work.
Thanks in advance.
In your for loops:
for(auto outermap : m_executormap) {
for(auto innermap : outermap.second) {
for(auto vec_element: innermap.second) {
You are using auto which defaults to a non-reference type so you are taking a copy of each element in the map/vector. Your changes are being applied to these temporary copies so are lost.
Simply change these to references to update the original lists:
for(auto& outermap : m_executormap) {
for(auto& innermap : outermap.second) {
for(auto& vec_element: innermap.second) {
I don't know if this has happened to some of you guys. I haven't started programming because "I don't know where to start". I want to make a platform video game, and 8 bits one. Yeah it will take a lot of time and skill, but I always like to jump to the complicated stuff.
I'm the kind of person that likes to use the latest of the latest programs. So I use Visual Studio 2017, however SFML is up to VS2015. Is there a way to use SFML is VS2017? What can I do?
First, congrats on starting your journey into programming!
However, as someone who has tutored many kids who have the same ambition (e.g. learning C++ to make a video game), I'd recommend you start down a simpler path.
I won't go into trying to learn C# or Java or some other language, as I, and many others, actually started with C; it's not about learning the particular language, it's about understanding the system as a whole. The concept of a thread, object, loops or functions doesn't change, it's how it's utilized that changes between languages.
I'm the kind of person that likes to use the latest of the latest programs.
While this might typically be good for most programs, due to bug fixes or other enhancements, this is not true for development environments. When you update Visual Studio, you're typically updating your entire toolchain: compiler, linker, SDK's, etc.
This means the possibility to introduce either a buggy compiler, or have code flagged as deprecated, among other issues to be considered. Especially when developing something like a game.
I haven't started programming because "I don't know where to start"
Here's a simple "war" card game that emulates 2 players; it automatically plays war until the game is won. It repeats this until an interrupt signal is received (CTRL+C) and it prints out the maximum number of turns during any game, as well as the minimum number of turns in any game played by our 'auto-players'.
It's in C++, can be modified to take user input for a blackjack or poker game, and you can build it on any system simply enough.
This code is meant for teaching, so you can take this code, modify it, build it, run it, and understand what's happening in each of those steps.
From there, you can learn more, ask more questions, and eventually you'll be able to make your 2D platform game with SFML.
war.cpp
#include <iostream>
#include <string>
#include <sstream>
#include <deque>
#include <algorithm>
#include <ctime>
#include <cstdlib>
#include <csignal>
#define print(v) std::cout << v
#define printl(v) std::cout << v << std::endl
namespace util {
class random {
public:
random() { std::srand(std::time(0)); }
int get(int max_val) { return std::rand() % max_val; }
};
}
namespace battle {
class suit {
public:
typedef enum enum_t {
HEART,
DIAMOND,
CLUB,
SPADE,
END
} enum_t;
suit() : m_val(END) {}
suit(const suit& cp) : m_val(cp.m_val) {}
explicit suit(enum_t val) : m_val(val) {}
suit& operator=(const suit& other)
{
this->m_val = other.m_val;
return *this;
}
suit& operator=(const enum_t& other)
{
this->m_val = other;
return *this;
}
bool operator==(const enum_t& other) { return (this->m_val == other); }
bool operator!=(const enum_t& other) { return (this->m_val != other); }
bool operator<(const enum_t& other) { return (this->m_val < other); }
bool operator>(const enum_t& other) { return (this->m_val > other); }
operator int() const { return static_cast<int>(this->m_val); }
operator enum_t() const { return this->m_val; }
friend std::ostream& operator<<(std::ostream& os, const battle::suit& val)
{
switch (val.m_val) {
case battle::suit::HEART: os << "♥"; break;
case battle::suit::DIAMOND: os << "♦"; break;
case battle::suit::CLUB: os << "♣"; break;
case battle::suit::SPADE: os << "♠"; break;
default: os << '?'; break;
}
return os;
}
private:
enum_t m_val;
};
class value {
public:
typedef enum enum_t {
ACE,
ONE,
TWO,
THREE,
FOUR,
FIVE,
SIX,
SEVEN,
EIGHT,
NINE,
JACK,
QUEEN,
KING,
END
} enum_t;
value() : m_val(END) {}
value(const value& cp) : m_val(cp.m_val) {}
explicit value(enum_t val) : m_val(val) {}
value& operator=(const value& other)
{
this->m_val = other.m_val;
return *this;
}
value& operator=(const enum_t& other)
{
this->m_val = other;
return *this;
}
bool operator==(const enum_t& other) { return (this->m_val == other); }
bool operator!=(const enum_t& other) { return (this->m_val != other); }
bool operator<(const enum_t& other) { return (this->m_val < other); }
bool operator>(const enum_t& other) { return (this->m_val > other); }
operator int() const { return static_cast<int>(this->m_val); }
operator enum_t() const { return this->m_val; }
friend std::ostream& operator<<(std::ostream& os, const battle::value& val)
{
switch (val.m_val) {
case battle::value::ACE: os << 'A'; break;
case battle::value::JACK: os << 'J'; break;
case battle::value::QUEEN: os << 'Q'; break;
case battle::value::KING: os << 'K'; break;
default: os << static_cast<int>(val); break;
}
return os;
}
private:
enum_t m_val;
};
class card {
public:
card() : m_val(value::END), m_suit(suit::END) {}
card(const card& cp) : m_val(cp.m_val), m_suit(cp.m_suit) {}
card(int suit, int val) : m_val(static_cast<value::enum_t>(val)), m_suit(static_cast<suit::enum_t>(suit)) {}
card(suit::enum_t suit, value::enum_t val) : m_val(val), m_suit(suit) {}
~card() {}
card& operator=(const card& other)
{
this->m_val = other.m_val;
this->m_suit = other.m_suit;
return *this;
}
bool operator==(const card& other)
{
return (this->m_val == other.m_val && this->m_suit == other.m_suit);
}
bool operator!=(const card& other)
{
return !(this->m_val == other.m_val && this->m_suit == other.m_suit);
}
bool operator<(const card& other)
{
if (this->m_val == value::ACE) {
return false;
}
return (this->m_val < other.m_val);
}
bool operator>(const card& other)
{
if (this->m_val == value::ACE) {
return (other.m_val != value::ACE);
}
return (this->m_val > other.m_val);
}
bool empty() const
{
return (this->m_val == value::END ||
this->m_suit == suit::END);
}
friend std::ostream& operator<<(std::ostream& os, const card& obj)
{
os << obj.m_val << obj.m_suit;
return os;
}
int suit() const
{
return this->m_suit;
}
value::enum_t value() const
{
return this->m_val;
}
private:
battle::value m_val;
battle::suit m_suit;
};
class deck {
public:
static const std::size_t DECK_SIZE = 52;
static const std::size_t HALF_DECK = 26;
deck() : m_rand(), m_deck() {}
~deck() {}
bool add(card& c)
{
if (c.empty()) { return false; }
const std::size_t idx = static_cast<std::size_t>(c.suit());
itr_t cv = std::find(this->m_deck.begin(), this->m_deck.end(), c);
bool found = (cv != this->m_deck.end());
if (!found) {
this->m_deck.insert(this->m_deck.begin(), c);
return true;
}
return false;
}
void add_init(card c)
{
const std::size_t idx = static_cast<std::size_t>(c.suit());
this->m_deck.push_back(c);
}
card deal()
{
if (!this->empty()) {
std::size_t cnt = this->m_deck.size();
if ((cnt == 0) || ((cnt - 1) == 0)) {
card ret(this->m_deck[0]);
this->m_deck.erase(this->m_deck.begin());
return ret;
}
cnt = this->m_rand.get(cnt);
card ret = this->m_deck[cnt];
this->remove_it(ret);
return ret;
}
return card();
}
bool empty() const
{
return this->m_deck.empty();
}
void fill()
{
printl("Filling deck");
for (int s = suit::HEART; s < suit::END; ++s) {
for (int v = value::ACE; v < value::END; ++v) {
this->add_init(battle::card(s, v));
}
}
}
void top_to_back()
{
card& c = this->m_deck[this->m_deck.size()-1];
for (itr_t s = this->m_deck.begin(); s != this->m_deck.end(); ++s) {
if ((*s) == c) {
this->m_deck.erase(s);
break;
}
}
this->m_deck.insert(this->m_deck.begin(), c);
}
void remove(const card& c)
{
if (!this->empty()) {
this->remove_it(c);
}
}
std::size_t size() const
{
return this->m_deck.size();
}
card operator[](std::size_t idx) const
{
return this->m_deck[idx];
}
private:
deck(const deck& cp); // = delete
deck& operator=(const deck& other); // = delete
util::random m_rand;
std::deque<card> m_deck;
typedef std::deque<card>::iterator itr_t;
void remove_it(const card& c)
{
for (itr_t s = this->m_deck.begin(); s != this->m_deck.end(); ++s) {
if ((*s) == c) {
this->m_deck.erase(s);
break;
}
}
}
};
class player {
public:
player() : m_hand(), m_name("NaN"), m_id(), m_tot_add(0), m_tot_rem(0), m_won(0), m_other(0) {}
player(std::size_t id) : m_hand(), m_name(), m_id(id), m_tot_add(0), m_tot_rem(0), m_won(0), m_other(0)
{
std::stringstream ss;
ss << "Player " << id;
this->m_name = ss.str();
}
void add_init(card c)
{
this->m_hand.add_init(c);
}
bool add_card(card c)
{
++this->m_tot_add;
return this->m_hand.add(c);
}
void add_cards(const std::deque<card>& cards)
{
std::deque<card>::const_iterator start = cards.begin();
while (start != cards.end()) {
this->add_card(*start);
++start;
}
}
bool empty() const
{
return this->m_hand.empty();
}
std::deque<card> battle_group() const
{
std::deque<card> ret;
if (!this->empty()) {
std::size_t top_idx = this->m_hand.size()-1;
for (std::size_t i = 0; i < 4 && top_idx > 0; ++i) {
ret.push_back(this->m_hand[--top_idx]);
}
}
return ret;
}
std::size_t hand_size() const
{
return this->m_hand.size();
}
std::size_t id() const
{
return this->m_id;
}
std::string name() const
{
return this->m_name;
}
void print_hand() const
{
for (std::size_t i = 0; i < this->m_hand.size(); ++i) {
std::cout << this->m_hand[i] << std::endl;
}
}
void remove_card(card c)
{
++this->m_tot_rem;
this->m_hand.remove(c);
}
void remove_cards(const std::deque<card>& cards)
{
std::deque<card>::const_iterator start = cards.begin();
while (start != cards.end()) {
this->remove_card(*start);
++start;
}
}
void print_stats()
{
printl("---" << this->name() << "---");
printl("Hand: " << this->m_hand.size());
printl("Wins: " << this->m_won);
printl("Took: " << this->m_tot_add);
printl("Lost: " << this->m_tot_rem);
}
void set_other_play(player& other)
{
this->m_other = &other;
}
void takes(card& c)
{
printl(this->m_name << " takes " << c);
this->m_hand.top_to_back();
this->m_other->remove_card(c);
this->add_card(c);
}
card top_card() const
{
if (this->empty()) { return card(); }
return this->m_hand[this->m_hand.size()-1];
}
void won_battle(card& c)
{
printl(this->m_name << " won the battle!");
this->takes(c);
++this->m_won;
}
void won_battle(const std::deque<card>& cards)
{
std::deque<card>::const_iterator start = cards.begin();
this->m_hand.top_to_back();
print(this->m_name << " won the battle, takes");
while (start != cards.end()) {
print(" " << *start);
this->m_other->remove_card(*start);
this->add_card(*start);
++start;
}
printl("");
++this->m_won;
}
private:
deck m_hand;
std::string m_name;
std::size_t m_id;
std::size_t m_tot_add;
std::size_t m_tot_rem;
std::size_t m_won;
player* m_other;
};
class game {
public:
game() : m_deck(), m_p1(1), m_p2(2), m_turns(0), m_battles(0)
{
this->m_p1.set_other_play(this->m_p2);
this->m_p2.set_other_play(this->m_p1);
this->m_deck.fill();
printl("Dealing cards");
for (std::size_t i = 0; i < deck::HALF_DECK; ++i) {
this->m_p1.add_init(this->m_deck.deal());
this->m_p2.add_init(this->m_deck.deal());
}
}
std::size_t dobattle(battle::card& c1, battle::card& c2)
{
printl("BATTLE!!!!");
++this->m_battles;
std::size_t sz1 = this->m_p1.hand_size();
std::size_t sz2 = this->m_p2.hand_size();
if (sz2 <= 1 && sz1 > 1) {
this->m_p1.won_battle(c2);
return this->m_p1.id();
}
if (sz1 <= 1 && sz2 > 1) {
this->m_p2.won_battle(c1);
return this->m_p2.id();
}
std::deque<battle::card> t1 = this->m_p1.battle_group();
std::deque<battle::card> t2 = this->m_p2.battle_group();
printl(this->m_p1.name() << ": " << t1.back() << ", " << this->m_p2.name() << ": " << t2.back());
if (t1.back() > t2.back()) {
this->m_p1.won_battle(t2);
return this->m_p1.id();
} else if (t1.back() < t2.back()) {
this->m_p2.won_battle(t1);
return this->m_p2.id();
} else { // another battle
this->m_p1.remove_card(c1); this->m_p1.remove_cards(t1);
this->m_p2.remove_card(c2); this->m_p2.remove_cards(t2);
if (this->dobattle(t1.back(), t2.back()) == this->m_p1.id()) {
this->m_p1.add_card(c1); this->m_p1.add_cards(t1);
this->m_p2.add_card(c2); this->m_p2.add_cards(t2);
this->m_p1.won_battle(t2);
return this->m_p1.id();
} else {
this->m_p1.add_card(c1); this->m_p1.add_cards(t1);
this->m_p2.add_card(c2); this->m_p2.add_cards(t2);
this->m_p2.won_battle(t1);
return this->m_p2.id();
}
}
return 0;
}
void play()
{
battle::card c1, c2;
while (true) {
if (this->check_win()) break;
c1 = this->m_p1.top_card();
c2 = this->m_p2.top_card();
printl(this->m_p1.name() << ": " << c1 << ", " << this->m_p2.name() << ": " << c2);
if (c1 < c2) {
this->m_p2.takes(c1);
} else if (c1 > c2) {
this->m_p1.takes(c2);
} else { // c1 == c2
this->dobattle(c1, c2);
}
++this->m_turns;
if (this->check_win()) break;
}
printl("");
printl("Game over!");
printl("");
}
void print_stats()
{
printl("----Stats----");
printl("Turns: " << this->m_turns);
printl("Battles: " << this->m_battles);
this->m_p1.print_stats();
this->m_p2.print_stats();
}
std::size_t turns() const { return this->m_turns; }
std::size_t battles() const { return this->m_battles; }
private:
deck m_deck;
player m_p1;
player m_p2;
std::size_t m_turns;
std::size_t m_battles;
bool check_win() const
{
if (this->m_p1.empty() || this->m_p2.empty()) {
if (this->m_p1.empty() && !this->m_p2.empty()) {
printl(this->m_p2.name() << " WINS!");
} else if (!this->m_p1.empty() && this->m_p2.empty()) {
printl(this->m_p1.name() << " WINS!");
} else {
printl("TIE?");
}
return true;
}
return false;
}
};
}
static volatile bool m_stop;
static void sig_hand(int sig) {
if (sig == SIGINT) { m_stop = true; }
}
int main(int argc, char* argv[])
{
std::size_t x = ~0;
std::size_t n = 0;
std::size_t g = 0;
const std::size_t MAX = 8; // 7*4 = 28
std::signal(SIGINT, sig_hand);
while ((x > MAX) && !m_stop) {
battle::game game;
game.play();
++g;
game.print_stats();
if (game.turns() < x) {
x = game.turns();
std::cerr << "least: " << x << std::endl;
}
if (n < game.turns()) {
n = game.turns();
std::cerr << "most: " << n << std::endl;
}
}
//printl("Done! Games played: " << g << ", Least turns: " << x << ", Most turns: " << n);
std::cerr << "Done! Games played: " << g << ", Least turns: " << x << ", Most turns: " << n << std::endl;
return 0;
}
Hope that can help.
Just a note to say SFML now works fine with VS2017.
I have version 2.5 binaries no need to compile.
See instructions here:
https://www.sfml-dev.org/tutorials/2.5/start-vc.php
I have my own smart pointer class realization.
template<typename Pointee>
class SmartPtr {
private:
Pointee* _pointee;
SmartPtr(SmartPtr &);
public:
explicit SmartPtr(Pointee * pt = 0);
~SmartPtr();
SmartPtr& operator=(SmartPtr&);
operator Pointee*() const { return *_pointee; }
bool operator!() const { return _pointee != 0; }
bool defined() const { return _pointee != 0; }
Pointee* operator->() const { return _pointee; }
Pointee& operator*() const { return *_pointee; }
Pointee* get() const { return _pointee; }
Pointee* release();
void reset(Pointee * pt = 0);
};
template<typename Pointee>
SmartPtr<Pointee>::SmartPtr(SmartPtr &spt) :_pointee(spt.release()) {
return;
}
template<typename Pointee>
SmartPtr<Pointee>::SmartPtr(Pointee * pt) : _pointee(pt) {
return;
}
template<typename Pointee>
SmartPtr<Pointee>::~SmartPtr() {
delete _pointee;
}
template<typename Pointee>
SmartPtr<Pointee>& SmartPtr<Pointee>::operator=(SmartPtr &source)
{
if (&source != this)
reset(source.release());
return *this;
}
template<typename Pointee>
Pointee * SmartPtr<Pointee>::release() {
Pointee* oldSmartPtr = _pointee;
_pointee = 0;
return oldSmartPtr;
}
template<typename Pointee>
void SmartPtr<Pointee>::reset(Pointee * pt) {
if (_pointee != pt)
{
delete _pointee;
_pointee = pt;
}
return;
}
In main.cpp I can do this:
SmartPtr<Time> sp1(new Time(0, 0, 1));
cout << sp1->hours() << endl;
Time it's my own class for testing. It has method hours() which show in console count of hours I set in constructor.
But when I want have nested smart pointers I need do this:
SmartPtr<SmartPtr<Time>> sp2(new SmartPtr<Time>(new Time(0,0,1)));
cout << sp2->operator->()->hours() << endl;
How can I do nested smart pointers but without using operator->()? Just like this:
SmartPtr<SmartPtr<Time>> sp2(new SmartPtr<Time>(new Time(0,0,1)));
cout << sp2->hours() << endl;
It can also be not only nesting level 2, but any for example:
SmartPtr<SmartPtr<SmartPtr<Time>>> sp3(new SmartPtr<SmartPtr<Time>>(new SmartPtr<Time>(new Time(0, 0, 1))));
And we should use:
cout << sp3->hours() << endl;
Instead of:
cout << sp3->operator->()->operator->()->hours() << endl;
You can't use operator-> one time to reach down several layers, unless you specialize Pointee to recognize SmartPtr types so operator-> can be written recursively.
Otherwise, just use your operator* instead to clean up all those nested operator->() calls:
cout << (*(*(*sp3))).hours() << endl;
Or
cout << (*(*sp3))->hours() << endl;
So I have such definition on map class on vector, it works good except for post-incrementation, which doesn't work as it should. You can see in example that variable a should be equal to 10 (post-incremented after assignment). But it's equal to 11. I have no idea how to fix that.
#include <iostream>
#include <string>
#include <vector>
using namespace std;
template<class T>
class Map {
class Cref {
friend class Map;
Map& m;
string key;
T value;
public:
operator double() {
return m.read(key);
};
Map::Cref & operator=(double num) {
m.write(key, num);
return *this;
};
Map::Cref & operator++(int) {
Cref c(*this);
m.increment(key, value);
return c;
}
Cref(Map& m, string a)
: m(m),
key(a) {};
};
public:
class Unitialized {};
struct Record {
string key;
T value;
};
vector<Record> data;
Map() {}
~Map() {}
bool ifexist(string k) {
for (int i = 0; i < data.size(); i++) {
if (data.at(i).key == k)
return 1;
}
return 0;
}
Cref operator[](string key) {
return Map::Cref( * this, key);
}
private:
void increment(string key, T value) {
if (ifexist(key) == 0) {
throw Unitialized();
}
for (int i = 0; i < data.size(); i++) {
if (data.at(i).key == key)
data.at(i).value += 1;
}
}
void write(string key, T value) {
if (ifexist(key) == 1) {
cout << "Element already exist" << endl;
return;
}
Record r;
r.key = key;
r.value = value;
data.push_back(r);
}
double read(string key) {
if (ifexist(key) == 0) {
throw Unitialized();
}
for (int i = 0; i < data.size(); i++) {
if (data.at(i).key == key)
return data.at(i).value;
}
return 0;
}
};
int main(int argc, char** argv) {
Map<int> m;
m["ala"] = 10;
int a = 0;
a = m["ala"]++;
cout << a << endl;
try {
cout << m["ala"] << endl;
cout << m["ola"] << endl;
} catch (Map<int>::Unitialized&) {
cout << "Unitialized element" << endl;
}
return 0;
}
Yes, I already fixed that, overloading of ++ operator should look like that :
T operator ++(int)
{
T ret = m.read(this->key);
m.increment(key, value);
return ret;
}
This fixes everything.