I am working on a RTS game using SDL. I have a woodyard class whose object will collect wood from nearby trees. In the class I create a vector called temp_trees and as an argument for the constructor I use a vector of tree objects that I pass in.
The woodyard constructor:
woodyard::woodyard(int x, int y, int HP, int id, vector<Tree> trees)
{
...
vector<Tree> temp_trees;
for(int i = 0; i < trees.size(); i++)
{
if((trees[i].xPos - 100) / 50 >= x - 5 && (trees[i].xPos - 100) / 50 <= x + 4)
{
if((trees[i].yPos - 100) / 50 >= y - 5 && (trees[i].yPos - 100) / 50 <= y + 4)
{
temp_trees.push_back(trees[i]);
}
}
}
collect_control = 0;
no = 0;
}
the collect_wood function:
void woodyard::collect_wood(){
if(no == 5)
{
temp_trees[collect_control].drewno -= 1;
if(temp_trees[collect_control].drewno <= 0){
collect_control++;
temp_trees.erase(temp_trees.begin());
}}
no++;
if(no >= 10){
no = 0;
}}
The program crashes just after start.
Can anybody see any errors in this code??
PS: I suppose that there might be something wrong with copping elements from one vector to another in the constructor.
The constructor doesn't contain any illegal operation.
And collect_wood(), although unintelligible, doesn't contain any obvious reason for making it crash.
Which is the value of collect_control? Do you check if it is < temp_trees.size()? Being aware that temp_trees.size() keep changing since you are erasing elements.
Probably collect_control shouldn't be incremented after the erase: all elements shift back, and collect_control after the erase is already pointing to the next element.
Note: Consider that temp_trees.erase(temp_trees.begin()); is one of the most inefficient things you could do with a vector (deleting the first element).
In the woodyard constructor, you are declaring a temporary, function-scoped variable "temp_trees".
woodyard::woodyard(int x, int y, int HP, int id, vector<Tree> trees)
{
...
vector<Tree> temp_trees;
If you have a vector member called temp_trees, this declaration is hiding it. So your member function is NOT seeing the same vector:
void woodyard::collect_wood(){
if(no == 5)
{
temp_trees[collect_control].drewno -= 1;
Also, without seeing the rest of the code, I wouldn't know how you are ensuring that there are at least "collect_control" members in the vector.
#include <assert.h>
...
assert(collect_control < temp_trees.size());
or if you're using visual studio you can do
if(collect_control >= temp_trees.size())
DebugBreak();
"size()" is a 1-based value but array index operators are zero based. That means, when there is one entry in the vector, it will be vector[0]. If the vector is empty, vector[0] is illegal - it does not exist. And emptiness is denoted by size being 0. size must always be greater than the element index you are trying to access.
Related
I have an array of values e.g. 1, 4, 7, 2.
I also have another array of values and I want to add its values to this first array, but only when they all are different from all values that are already in this array. How can I check it? I've tried many types of loops, but I always ended with an iteration problem.
Could you please tell me how to solve this problem? I code in c++.
int array1[7] = {2,3,7,1,0};
int val1 = rand() % 10;
int val2 = rand() % 10;
int array2[2] = {val1, val2};
and I am trying to put every value from array2 into array1. I tried loop
for (int x:array2)
{
while((val1 && val2) == x)
{
val1 = rand() % 10;
val2 = rand() % 10;
}
}
and many more, but still cannot figure it out. I have this problem because I may have various number of elements for array2. So it makes this "&&" solution infinite.
It is just a sample to show it more clearly, my code has much more lines.
Okay, you have a few problems here. If I understand the problem, here's what you want:
A. You have array1 already populated with several values but with space at the end.
1. How do you identify the number of entries in the array already versus the extras?
B. You have a second array you made from two random values. No problem.
You want to append the values from B to A.
2. If initial length of A plus initial length of B is greater than total space allocated for A, you have a new problem.
Now, other people will tell you to use the standard template library, but if you're having problems at this level, you should know how to do this yourself without the extra help from a confusing library. So this is one solution.
class MyArray {
public:
int * data;
int count;
int allocated;
MyArray() : data(nullptr), count(0), allocated(0) {}
~MyArray() { if (data != nullptr) free(data); }
// Appends value to the list, making more space if necessary
void add(int value) {
if (count >= allocated) {
// Not enough space, so make some.
allocated += 10;
data = (data == nullptr) malloc(allocated * sizeof(int))
: realloc)data, allocated * sizeof(int));
}
data[count++] = value;
}
// Adds value only if not already present.
void addUnique(int value) {
if (indexOf(value) < 0) {
add(value);
}
}
// Returns the index of the value, if found, else -1
int indexOf(int value) {
for (int index = 0; index < count; ++index) {
if (data[index] == value) {
return index;
}
}
return -1;
}
}
This class provides you a dynamic array of integers. It's REALLY basic, but it teaches you the basics. It helps you understand about allocation / reallocating space using old-style C-style malloc/realloc/free. It's the sort of code I was writing back in the 80s.
Now, your main code:
MyArray array;
array.add(2);
array.add(3);
array.add(7);
// etc. Yes, you could write a better initializer, but this is easy to understand
MyArray newValues;
newValues.add(rand() % 10);
newValues.add(rand() % 10);
for (int index = 0; index < newValues.count; ++index) {
array.addUnique(newValues.data[index]);
}
Done.
The key part of this is the addUnique function, which simply checks first whether the value you're adding already is in the array. If not, it appends the value to the array and keeps track of the new count.
Ultimately, when using integer arrays like this instead of the fancier classes available in C++, you HAVE TO keep track of the size of the array yourself. There is no magic .length method on int[]. You can use some magic value that indicates the end of the list, if you want. Or you can do what I did and keep two values, one that holds the current length and one that holds the amount of space you've allocated.
With programming, there are always multiple ways to do this.
Now, this is a lot of code. Using standard libraries, you can reduce all of this to about 4 or 5 lines of code. But you're not ready for that, and you need to understand what's going on under the hood. Don't use the fancy libraries until you can do it manually. That's my belief.
The two structures used in my code, one is nested
struct Class
{
std::string name;
int units;
char grade;
};
struct Student
{
std::string name;
int id;
int num;
double gpa;
Class classes[20];
};
I am trying to figure out a way to sort the structures within the all_students[100] array in order of their ID's in ascending order. My thought was, to start counting at position 1 and then compare that to the previous element. If it was smaller than the previous element then I would have a temporary array of type Student to equate it to, then it would be a simple matter of switching them places within the all_students array. However, when I print the results, one of the elements ends up being garbage numbers, and not in order. This is for an intermediate C++ class in University and we are not allowed to use pointers or vectors since he has not taught us this yet. Anything not clear feel free to ask me.
The function to sort the structures based on ID
void sort_id(Student all_students[100], const int SIZE)
{
Student temporary[1];
int counter = 1;
while (counter < SIZE + 1)
{
if (all_students[counter].id < all_students[counter - 1].id)
{
temporary[0] = all_students[counter];
all_students[counter] = all_students[counter - 1];
all_students[counter - 1] = temporary[0];
counter = 1;
}
counter++;
}
display(all_students, SIZE);
}
There are a few things wrong with your code:
You don't need to create an array of size 1 to use as a temporary variable.
Your counter will range from 1 to 100, you will go out of bounds: the indices of an array of size 100 range from 0 to 99.
The following solution uses insertion sort to sort the array of students, it provides a faster alternative to your sorting algorithm. Note that insertion sort is only good for sufficiently small or nearly sorted arrays.
void sort_id(Student* all_students, int size)
{
Student temporary;
int i = 1;
while(i < size) // Read my note below.
{
temporary = all_students[i];
int j = i - 1;
while(j >= 0 && temporary.id < all_students[j].id)
{
all_students[j+1] = all_students[j]
j--;
}
all_students[j+1] = temporary;
i++;
}
display(all_students, size);
}
Note: the outer while-loop can also be done with a for-loop like this:
for(int i = 1; i < size; i++)
{
// rest of the code ...
}
Usually, a for-loop is used when you know beforehand how many iterations will be done. In this case, we know the outer loop will iterate from 0 to size - 1. The inner loop is a while-loop because we don't know when it will stop.
Your array of Students ranges from 0, 99. Counter is allowed to go from 1 to 100.
I'm assuming SIZE is 100 (in which case, you probably should have the array count also be SIZE instead of hard-coding in 100, if that wasn't just an artifact of typing the example for us).
You can do the while loop either way, either
while(counter < SIZE)
and start counter on 0, or
while (counter < SIZE+1)
and start counter on 1, but if you do the latter, you need to subtract 1 from your array subscripts. I believe that's why the norm (based on my observations) is to start at 0.
EDIT: I wasn't the downvoter! Also, just another quick comment, there's really no reason to have your temporary be an array. Just have
Student temporary;
I overlooked the fact that I was allowing the loop to access one more element than the array actually held. That's why I was getting garbage because the loop was accessing data that didn't exist.
I fixed this by changing while (counter < SIZE + 1)
to: while (counter < SIZE )
Then to fix the second problem which was about sorting, I needed to make sure that the loop started again from the beginning after a switch, in case it needed to switch again with a lower element. So I wrote continue; after counter = 1
I have a Deque that contains this kind of stucts.
struct New_Array {
array<array<int,4>,4> mytable;
int h;
};
In this stuct 2 different arrays may have same value of h.
deque<New_Array> Mydeque;
I also know how many different h are in the deque(the value of steps). And how many stucts are in the deque(Mydeque.size()).
I need to print one array for each h. Starting from h=0 till h=steps (steps is a known int value). Each array that is going to be printed must be the closer to the end of the deque.
I tried something like this:
void foo(deque<New_Array> Mydeque, int steps)
for(int i=0; i<steps; i++)
{
deque<New_Array>::iterator it;
it = find(Mydeque.begin(),Mydeque.end(),i);
PrintBoard(*it); // This if a function where you enter the New_Array struct
// and it prints the array
}
}
The above gives me : error C2679: binary '==' : no operator found which takes a right-hand operand of type 'const bool' (or there is no acceptable conversion)
Or something like this:
void foo(deque<New_Array> Mydeque, int steps)
for(int i=0; i<steps; i++)
{
deque<New_Array>::iterator it;
for(unsigned int j=0;j<Mydeque.size();j++)
{
it = find_if(Mydeque.begin(),Mydeque.end(),Mydeque[j].h==i);
PrintBoard(*it);
break;
}
}
The above gives me: error C2064: term does not evaluate to a function taking 1 arguments
EDIT: The deque is not sorted. For each h an array should be printed. This array should be the one that is at this moment closer to the end of the deque.
Remember the last value and skip:
assert(!Mydeque.empty());
int old_h = Mydeque[0].h + 1; // make sure it's different!
for (std::size_t i = 0, end != Mydeque.size(); i != end; ++i)
{
if (Mydeque[i].h == old_h) continue;
print(Mydeque[i]);
old_h = Mydeque[i].h;
}
Firstly, note that you declare your std::array on the stack, so the storage will also be on the stack. This means that iterating over the structure involves loading a (4*4+1)*int for each comparison. If this is performance-sensitive, I would suggest using std::vector since the load will be only of the outer vector pointer and the h when only comparing h.
struct New_Array {
vector<vector<int,4>,4> mytable;
int h;
};
Secondly, if you need to access these tables through their h values, or access all the tables with a given h at once, make it easier for everyone and store them as vectors in a map, or a sorted vector of vectors:
std::map<int,std::vector<New_Array> > rolodex;
rolodex[someNewArray.h].push_back(someNewArray);
If you construct this in-order, then the first item in each vector will be the one to print:
for(auto it : rolodex) {
vector<New_Array> tablesForThisH = it->second;
if(tablesForThisH.begin() != tablesForThisH.end())
PrintBoard(it->second[0]);
}
Since std:map stores (and iterates) its keys in ascending (I think) order, this will run over the different h values in ascending order. Again it will only need to load the stack-stored struct, which is just the h int and the vector header (probably 12 bytes, as mentioned in this question).
Forgive me if the code is wrong, my stl is a little rusty.
Loop through the deque, and insert all elements into a map, using h as the key. Since your set of h values seems to be sequential, you can use a vector instead, but testing whether an element has already been found will be more difficult.
The solution is :
void Find_Solution_Path(deque<New_Array> Mydeque, int steps)
{
for(int i=0; i<steps+1; i++)
{
for(int j=Mydeque.size()-1;j>-1;j--)
{
if (Mydeque[j].h==i)
{
PrintBoard(Mydeque[j]);
cout<<endl;
break;
}
}
}
}
I'm making a C++ game which requires me to initialize 36 numbers into a vector. You can't initialize a vector with an initializer list, so I've created a while loop to initialize it faster. I want to make it push back 4 of each number from 2 to 10, so I'm using an int named fourth to check if the number of the loop is a multiple of 4. If it is, it changes the number pushed back to the next number up. When I run it, though, I get SIGABRT. It must be a problem with fourth, though, because when I took it out, it didn't give the signal.
Here's the program:
for (int i; i < 36;) {
int fourth = 0;
fourth++;
fourth%=4;
vec.push_back(i);
if (fourth == 0) {
i++;
}
}
Please help!
You do not initialize i. Use for (int i = 0; i<36;). Also, a new variable forth is allocated on each iteration of the loop body. Thus the test fourth==0 will always yield false.
I want to make it push back 4 of each number from 2 to 10
I would use the most straight forward approach:
for (int value = 2; value <= 10; ++value)
{
for (int count = 0; count < 4; ++count)
{
vec.push_back(value);
}
}
The only optimization I would do is making sure that the capacity of the vector is sufficient before entering the loop. I would leave other optimizations to the compiler. My guess is, what you gain by omitting the inner loop, you lose by frequent modulo division.
You did not initialize i, and you are resetting fourth in every iteration. Also, with your for loop condition, I do not think it will do what you want.
I think this should work:
int fourth = 0;
for (int i = 2; i<=10;) {
fourth++;
fourth%=4;
vec.push_back(i);
if (fourth==0) {
i++;
}
}
I've been able to create a static array declaration and pass that array into the vector at initialization without issue. Pretty clean too:
const int initialValues[36] = {0,1,2...,35};
std::vector foo(initialValues);
Works with constants, but haven't tried it with non const arrays.
I've developed a method called "rotate" to my stack object class. What I did was that if the stack contains elements: {0,2,3,4,5,6,7} I would needed to rotate the elements forwards and backwards.
Where if i need to rotate forwards by 2 elements, then we would have, {3,4,5,6,7,0,2} in the array. And if I need to rotate backwards, or -3 elements, then, looking at the original array it would be, {5,6,7,0,2,3,4}
So the method that I have developed works fine. Its just terribly ineffecient IMO. I was wondering if I could wrap the array around by using the mod operator? Or if their is useless code hangin' around that I havent realized yet, and so on.
I guess my question is, How can i simplify this method? e.g. using less code. :-)
void stack::rotate(int r)
{
int i = 0;
while ( r > 0 ) // rotate postively.
{
front.n = items[top+1].n;
for ( int j = 0; j < bottom; j++ )
{
items[j] = items[j+1];
}
items[count-1].n = front.n;
r--;
}
while ( r < 0 ) // rotate negatively.
{
if ( i == top+1 )
{
front.n = items[top+1].n;
items[top+1].n = items[count-1].n; // switch last with first
}
back.n = items[++i].n; // second element is the new back
items[i].n = front.n;
if ( i == bottom )
{
items[count-1].n = front.n; // last is first
i = 0;
r++;
continue;
}
else
{
front.n = items[++i].n;
items[i].n = back.n;
if ( i == bottom )
{
i = 0;
r++;
continue;
}
}
}
}
Instead of moving all the items in your stack, you could change the definition of 'beginning'. Have an index that represents the first item in the stack, 0 at the start, which you add to and subtract from using modular arithmetic whenever you want to rotate your stack.
Note that if you take this approach you shouldn't give users of your class access to the underlying array (not that you really should anyway...).
Well, as this is an abstraction around an array, you can store the "zero" index as a member of the abstraction, and index into the array based on this abstract notion of the first element. Roughly...
class WrappedArray
{
int length;
int first;
T *array;
T get(int index)
{
return array[(first + index) % length];
}
int rotateForwards()
{
first++;
if (first == length)
first = 0;
}
}
You've gotten a couple of reasonable answers, already, but perhaps one more won't hurt. My first reaction would be to make your stack a wrapper around an std::deque, in which case moving an element from one end to the other is cheap (O(1)).
What you are after here is a circular list.
If you insist on storing items in an array just use top offset and size for access. This approach makes inserting elements after you reached allocated size expensive though (re-allocation, copying). This can be solved by using doubly-linked list (ala std::list) and an iterator, but arbitrary access into the stack will be O(n).
The function rotate below is based on reminders (do you mean this under the 'mod' operation?)
It is also quite efficient.
// Helper function.
// Finds GCD.
// See http://en.wikipedia.org/wiki/Euclidean_algorithm#Implementations
int gcd(int a, int b) {return b == 0 ? a : gcd(b, a % b);}
// Number of assignments of elements in algo is
// equal to (items.size() + gcd(items.size(),r)).
void rotate(std::vector<int>& items, int r) {
int size = (int)items.size();
if (size <= 1) return; // nothing to do
r = (r % size + size) % size; // fits r into [0..size)
int num_cycles = gcd(size, r);
for (int first_index = 0; first_index < num_cycles; ++first_index) {
int mem = items[first_index]; // assignment of items elements
int index = (first_index + r) % size, index_prev = first_index;
while (index != first_index) {
items[index_prev] = items[index]; // assignment of items elements
index_prev = index;
index = (index + r) % size;
};
items[index_prev] = mem; // assignment of items elements
}
}
Of course if it is appropriate for you to change data structure as described in other answers, you can obtain more efficient solution.
And now, the usual "it's already in Boost" answer: There is a Boost.CircularBuffer
If for some reason you'd prefer to perform actual physical rotation of array elements, you might find several alternative solutions in "Programming Pearls" by Jon Bentley (Column 2, 2.3 The Power of Primitives). Actually a Web search for Rotating Algorithms 'Programming Pearls' will tell you everything. The literal approach you are using now has very little practical value.
If you'd prefer to try to solve it yourself, it might help to try looking at the problem differently. You see, "rotating an array" is really the same thing as "swapping two unequal parts of an array". Thinking about this problem in the latter terms might lead you to new solutions :)
For example,
Reversal Approach. Reverse the order of the elements in the entire array. Then reverse the two parts independently. You are done.
For example, let's say we want to rotate abcdefg right by 2
abcdefg -> reverse the whole -> gfedcba -> reverse the two parts -> fgabcde
P.S. Slides for that chapter of "Programming Pearls". Note that in Bentley's experiments the above algorithm proves to be quite efficient (among the three tested).
I don't understand what the variables front and back mean, and why you need .n. Anyway, this is the shortest code I know to rotate the elements of an array, which can also be found in Bentley's book.
#include <algorithm>
std::reverse(array , array + r );
std::reverse(array + r, array + size);
std::reverse(array , array + size);