I'm a beginner to the STL and I used it to make a simple hangman project. Full code here: https://github.com/SamtheSaint/Hangman.
I needed to detect multiple occurrences of letters in a vector but I could not and ended up working around it to finish the program. Is there a simpler way to do this?
iter = find(gameWord.begin(), gameWord.end(), playGuess);
if (iter == gameWord.end()) {
guesses--;
}
while (iter != gameWord.end()) {
iter = find(gameWord.begin(), gameWord.end(), playGuess);
if (iter != gameWord.end()) {
int index = distance(gameWord.begin(), iter);
hiddenWord[index] = playGuess;
*iter = '0'; // so program can find the next one
}
}
I end up destroying gameWord vector so I have to make a copy(which I call checkWord) at the beginning of the loop it's in so I can compare it later to hiddenWord.
You do not need std::map.
You just need two std::string (one which is expression to guess, the other one is the pattern shown to the player) which will be kept in synchronization. This mean you should enclose them in class.
Do not make thing more complicated then it is necessary.
This is quite simple:
class Hangman {
public:
constexpr SecretChar = '_';
Hangman(const std::string& secret)
: mSecret(secret)
{
provideMask();
}
bool guess(char ch) {
auto index = mSecret.find(ch);
if (index == std::string::npos) return false;
if (already_guessed(index)) return false;
updateMaskWith(ch);
return true;
}
std::string mask() const {
return mMask;
}
private:
void provideMask() {
mask = mSecret;
std::replace_if(mMask.begin(), mMask.end(), std::isalpha, SecretChar);
}
bool already_guessed(int index) {
return mMask[index] != SecretChar;
}
void updateMaskWith(char ch) {
auto index = mSecret.find(ch);
while (index == std::string::npos) {
mMask[index] = ch;
index = mSecret.find(ch, index + 1);
}
}
private:
std::string mSecret;
std::string mMask;
};
Now write seperate code which will use this and keep score and you are almost done.
In my code I have a struct, similar to the following:
struct basket {
std::string a;
std::string b;
std::string c;
std::string d;
};
I want to be able to compare two structs and determine > 0, < 0, == 0 by comparing the concatenation of all of those strings
std::string total = (a+b+c+d);
However, I want to achieve this without doing the actual concatenation, because this comparison is used many times, and it ends up being a run-time bottleneck. I know that if that's the case, I should look into avoiding the use of strings, but for now I'd simply like to do this comparison easily without concatenating.
Right now, I use a giant if statement. For example compare string a from each instance of the struct, if they're the same, compare b, if they're the same, compare c, if they're the same then finally compare d, but I was wondering if there's a cleaner way to do this in c++ that doesn't have the runtime hit of concatenations.
Thank you.
If I understand you correctly, you want two structs to be equal if the concatenation of strings is equal, so
a == "hello", b == "there", ...
matches
a = "hel", b == "lothere", ...
I would do this using boost::range::join:
struct basket {
...
bool operator==(const basket& other) const
{
using namespace boost::range;
auto left = join(join(join(a, b), c), d);
auto right = join(join(join(other.a, other.b), other.c), other.d);
return equal(left, right); // http://www.boost.org/doc/libs/1_51_0/libs/range/doc/html/range/reference/algorithms/non_mutating/equal.html
}
};
boost::range::join (http://www.boost.org/doc/libs/1_57_0/libs/range/doc/html/range/reference/utilities/join.html) creates a joined range without doing the concatenation. It internally just iterates all the way across. The only additional overhead is checking for the end of the first range and moving to the second range, so it should be much faster than actually concatenating.
UPDATE:
I originally missed the desire for a strcmp style return. Unfortunately I can't find any standard algorithms that return a value like this. On the upside, though, it's easy enough to write. Here is the update version, with compare instead of equal:
#include <boost/range/join.hpp>
template <typename SinglePassRange1, typename SinglePassRange2>
int compare(const SinglePassRange1& left, const SinglePassRange2& right)
{
using namespace std;
auto leftIt = begin(left);
auto leftEnd = end(right);
auto rightIt = begin(right);
auto rightEnd = end(right);
for ( ; leftIt != leftEnd
&& rightIt != rightEnd
&& *leftIt == *rightIt
; ++leftIt, ++rightIt)
{
}
// should be safe since one-past-end for strings is '\0'
return static_cast<int>(*leftIt) - static_cast<int>(*rightIt);
}
struct basket {
std::string a;
std::string b;
std::string c;
std::string d;
int compare(const basket& other) const
{
using namespace boost::range;
auto left = join(join(join(a, b), c), d);
auto right = join(join(join(other.a, other.b), other.c), other.d);
return ::compare(left, right);
}
};
Tested on GCC 4.9.1 Ubuntu.
That compare free function should probably be called compareStringRanges or something since that implementation is only valid for strings. I'll leave that to the realm of individual aesthetics.
The easy way to work with these fields would be to use an array for fields' storage, rather than individual fields.
You can create a temporary array to simplify your code. Your implementation will almost surely put the std::array's data on the stack.
Illustration:
int compare(const basket &pOther) const {
const BasketStringRefs a(this->allStrings());
const BasketStringRefs b(pOther.allStrings());
// ...your evaluation here, involving iteration over a and b...
}
private:
typedef std::array<const std::string*, 4> BasketStringRefs;
BasketStringRefs allStrings() const {
return BasketStringRefs{{&a, &b, &c, &d}};
}
It'll be trouble to set up, but it'll be efficient: store a, b, c, and d in a single buffer. You can maintain pointers to each to keep track of where each begins (or if you know a max size, store them at relative locations 0, max size, max size*2, and max size+3).
When you compare baskets, compare their buffers, using a for loop that goes up to buffer size rather than a while that ends with the null character. When you get to a null character, you're done with that string; go on to the next one to see the next char you want to compare. If that happens 4 times, you've read all 4, and should quit that basket.
//baskets are a and b
for (int aIndex = 0, bindex = 0; aIndex < MAX && bIndex < MAX; ++aIndex, ++bIndex)
{
//if we reach null char for basket a, skip to next string in basket a. Same for b.
//if we run out of strings in basket a first, it's shorter
// and comes first in alpha order. Same for b.
//if we run out of strings in both baskets without finding any differences,
// return 0 for equal
//compare the next char in each buffer; if different, return -1 or 1 appropriately
}
I wrote a quick and dirty iterator for the concatenated string, just for fun:
#include "stdafx.h"
#include <iostream>
#include <assert.h>
class concatenation {
private:
std::string a, b, c, d;
public:
concatenation(){}
concatenation(const std::string &s1, const std::string &s2, const std::string &s3, const std::string &s4)
: a(s1), b(s2), c(s3), d(s4)
{}
class const_iterator {
private:
size_t stringnumber, stringposition;
const concatenation ⌖
public:
const_iterator(const concatenation &r, size_t n, size_t p) : target(r), stringnumber(n), stringposition(p) {}
bool operator ==(const const_iterator &rhs){ return stringnumber == rhs.stringnumber && stringposition == rhs.stringposition; }
bool operator !=(const const_iterator &rhs){ return !(*this == rhs); }
char operator *(){
switch (stringnumber){
case 0: return target.a[stringposition];
case 1: return target.b[stringposition];
case 2: return target.c[stringposition];
case 3: return target.d[stringposition];
default:
return '\0';
}
}
const_iterator& operator ++(){
size_t current_length;
switch (stringnumber){
case 0: current_length = target.a.size(); break;
case 1: current_length = target.b.size(); break;
case 2: current_length = target.c.size(); break;
case 3: current_length = target.d.size(); break;
default:
assert(0);
current_length = 0;
}
if (stringposition < current_length-1){
++stringposition;
} else {
stringposition = 0;
++stringnumber;
}
return *this;
}
};
const_iterator begin() const {
return const_iterator(*this, 0, 0);
}
const_iterator end() const {
return const_iterator(*this, 4, 0);
}
};
int compare(const concatenation &left, const concatenation &right){
concatenation::const_iterator p1 (left.begin());
concatenation::const_iterator p2 (right.begin());
while (p1 != left.end() && p2 != right.end() && (*p1)==(*p2)){
++p1;
++p2;
}
if (*p1 != *p2){
if (p1 == left.end() && p2 != right.end())
return -1;
if (p1 != left.end() && p2 == right.end())
return 1;
if (*p1 < *p2)
return -1;
else
return 1;
}
return 0;
}
int main()
{
concatenation test("hel", "lo ", "wor", "ld.");
for (concatenation::const_iterator pos = test.begin(); pos != test.end(); ++pos)
std::cout << *pos;
std::cout << std::endl;
{
// same
concatenation first("hello", " ", "world", ".");
concatenation second("hel", "lo ", "wor", "ld.");
if (0 != compare(first, second))
assert(0);
}
{
// first character different
concatenation first("hello", " ", "world", ".");
concatenation second("jel", "lo ", "wor", "ld.");
if (-1 != compare(first, second))
assert(0);
if (1 != compare(second, first))
assert(0);
}
{
// middle character different
concatenation first("hello", " ", "world", ".");
concatenation second("hel", "p! ", "wor", "ld.");
if (-1 != compare(first, second))
assert(0);
if (1 != compare(second, first))
assert(0);
}
{
// length different
concatenation first("hello", "", "", "");
concatenation second("hel", "lo ", "wor", "ld.");
if (-1 != compare(first, second))
assert(0);
if (1 != compare(second, first))
assert(0);
}
return 0;
}
I was wondering recently what the requirements were for range based for loops in c++11, as I had only ever seen examples of intended usage:
for (auto person : people)
{
cout << person.name << endl;
}
But given that a container need only have begin and end methods, but need not contain anything at all, would the below be considered 'bad practice' in any way? If nothing else, it is a fresh answer if someone asks you for a Fibonacci sequence in an interview!
#include <string>
#include <iostream>
#include <Windows.h>
using namespace std;
struct FibItr
{
FibItr(int cur = 1, int prev = 0) : mCur(cur), mPrev(prev) {}
FibItr & operator++()
{
mCur += mPrev;
mPrev = mCur - mPrev;
return *this;
}
int operator*(){ return mCur; }
bool operator!=(const FibItr & _rhs)
{
return mCur != _rhs.mCur || mPrev != _rhs.mPrev;
}
unsigned int mCur, mPrev;
};
struct Fib
{
FibItr begin() { return FibItr(); }
FibItr end() { return FibItr(0, 0); }
};
int main( int argc, char* argv[] )
{
for (auto num : Fib())
{
cout << num << endl;
Sleep(500);
}
return 0;
}
The question is not really about the auto for-loop but if it is reasonable to implement stranger kind of iterators. While there are corner-cases you can make a perfect good argument for implementing some operations as iterators (memoized fibonacci being a good example).
There are whole libraries devoted to turning iterators in something more, so some other people also think it is a good idea.
As an aside: Implementing an iterator is tricky business, which is why methods like this should be used with care. Boost.Iterator is a good set of helpers that can make that easier.
Target: There is text file (on HDD) containing integers divided with some kind of delimiter.
Example:
5245
234224
6534
1234
I need to read them into STL container.
int main(int argc, char * argv[]) {
using namespace std;
// 1. prepare the file stream
string fileName;
if (argc > 1)
fileName = argv[1];
else {
cout << "Provide the filename to read from: ";
cin >> fileName;
}
unique_ptr<ifstream, ifstream_deleter<ifstream>> ptrToStream(new ifstream(fileName, ios::out));
if (!ptrToStream->good()) {
cerr << "Error opening file " << fileName << endl;
return -1;
}
// 2. value by value reading will be too slow on large data so buffer data
typedef unsigned int values_type;
const int BUFFER_SIZE(4); // 4 is for testing purposes. 16MB or larger in real life
vector<values_type> numbersBuffer(BUFFER_SIZE);
numbersBuffer.insert(numbersBuffer.begin(), istream_iterator<values_type>(*ptrToStream), istream_iterator<values_type>());
// ...
The main drawback of this code is how can I handle the issue when file size is extremely large, so I cannot store all of it's contents in memory ?
I also do not want to use push_back as it is non efficient in comparison to interval insert.
So, the question is: how can I read not more than BUFFER_SIZE elements from the file effectively using STL?
The approach to limit reading from input iterators is to create a wrapper which counts the number of elements processed so far and whose end iterator compares to this number. Doing this generically isn't quite trivial, doing it specifically for std::istream_iterator<T> shouldn't be too hard. That said, I think the easiest way to do it is this:
std::vector<T> buffer;
buffer.reserve(size);
std::istreambuf_iterator<T> it(in), end;
for (std::vector<T>::size_type count(0), capacity(size);
it != end && count != capacity; ++it, ++count) {
buffer.push_back(*it);
}
I realize that you don't want to push_back() because it is allegedly slow. However, compared to the I/O operation I doubt that you'll be able to measure the small overhead, especially with typical implementation of the I/O library.
Just to round things off with an example of a wrapped iterator: below is an example how a counting wrapper for std::istream_iterator<T> could look like. There are many different ways this could be done, this is just one of them.
#include <iostream>
#include <iterator>
#include <vector>
#include <sstream>
template <typename T>
class counted_istream_iterator:
public std::iterator<std::input_iterator_tag, T, std::ptrdiff_t>
{
public:
explicit counted_istream_iterator(std::istream& in): count_(), it_(in) {}
explicit counted_istream_iterator(size_t count): count_(count), it_() {}
T const& operator*() { return *this->it_; }
T const* operator->() { return it_->it_.operator->(); }
counted_istream_iterator& operator++() {
++this->count_; ++this->it_; return *this;
}
counted_istream_iterator operator++(int) {
counted_istream_iterator rc(*this); ++*this; return rc;
}
bool operator== (counted_istream_iterator const& other) const {
return this->count_ == other.count_ || this->it_ == other.it_;
}
bool operator!= (counted_istream_iterator const& other) const {
return !(*this == other);
}
private:
std::ptrdiff_t count_;
std::istream_iterator<T> it_;
};
void read(int count)
{
std::istringstream in("0 1 2 3 4 5 6 7 8 9");
std::vector<int> vec;
vec.insert(vec.end(), counted_istream_iterator<int>(in),
counted_istream_iterator<int>(count));
std::cout << "size=" << vec.size() << "\n";
}
int main()
{
read(4);
read(100);
}
There is possible way to solve my problem:
// 2. value by value reading will be too slow on large data so buffer data
typedef unsigned int values_type;
const int BUFFER_SIZE(4);
vector<values_type> numbersBuffer;
numbersBuffer.reserve(BUFFER_SIZE);
istream_iterator<values_type> begin(*ptrToStream), end;
while (begin != end) {
copy_n(begin, BUFFER_SIZE, numbersBuffer.begin());
for_each(numbersBuffer.begin(), numbersBuffer.end(), [](values_type const &val){ std::cout << val << std::endl; });
++begin;
}
But it has one drawback. If input file contains the following:
8785
245245454545
7767
then 8785 will be read, but 245245454545 and 7767 will not, because 245245454545 cannot be converted to unsigned int. Error will be silent. :(
This might be an odd question, but how does one nicely loop over ALL values of a type. In particular the standard integral types such as unsigned short. A normal for loop construct presents a difficulty: what condition to use to exit the loop - because all values are valid.
Of course, there are several ways to get the job done. Exit on the last value then handle that after the loop. Use a bigger int to count. The question is, is there a more elegant way?
I worried about this very same issue once, and this is the best I could think of:
unsigned char c = 0;
do
{
printf("%d ", (int)c); //or whatever
} while (++c != 0);
One of the very few cases where I find the do..while syntax useful.
Note that technically it is only valid for unsigned types, as I am relying on the wrapping of values.
#include <limits>
int i = std::numeric_limits<int>::min();
do {
...
if(i == std::numeric_limits<int>::max())
break;
i++;
} while(true);
This is in contrast to a for() statement which translates to:
#include <limits>
int i = std::numeric_limits<int>::min();
while(true) {
if(i == std::numeric_limits<int>::max())
break;
...
i++;
};
If you want a pretty solution you can do this:
for(auto x : everyvalue<short>()) {
std::cout << x << '\n';
}
Where everyvalue is:
#include <limits>
template<typename T>
struct everyvalue {
struct iter {
T x;
bool flag;
inline iter operator++() {
if(x == std::numeric_limits<T>::max())
flag = true;
else
++x;
return *this;
}
inline T operator*() { return x;}
inline bool operator!=(iter& i) {return flag != i.flag;}
// note: missing some iterator requirements, still should work
};
inline iter begin() { return iter{std::numeric_limits<T>::min(),0}; }
inline iter end() { return iter{std::numeric_limits<T>::max(),1}; }
};
Otherwise a simple break would be preferred.
You can combine the value by which you increment with a flag to say you've reached the max so you don't increment past it:
for ( char i ( std::numeric_limits<char>::min() ), j ( 1 );
i != std::numeric_limits<char>::max() || j--;
i += j )
std::cout << ( int ) i << '\n';
but only elegant as in 'sophisticated' rather than 'clean simple lines'.
Look up the minimum and maximum values?
You can just use a larger type:
unsigned long i;
for (i = std::numeric_limits<unsigned short>::min();
i <= std::numeric_limits<unsigned short>::max();
i++)
I recently asked the same question about bools: How to write a `for` loop over bool values (false and true). You may look for the answers there. I then realized that since a for-loop iterating over all possible values would need to evaluate the condition one more time, you need an extra value (in any form - a bigger type, a second variable, etc) to properly distinguish all cases. And, a do-while loop works for this case because it needs exactly as many comparisons as there are distinct values.