I have been trying to work on this problem for quite some time but I seem to be stuck and not getting the results that are needed.
Lets say I want to stack some cards in my hand.
I have to use an array of structs, because each card has a name as well.
struct Creature {
std::string name;
int x, y;
};
In my main.cpp, I make the variable
Creature c[MAX_CARDS]
I can only hold 100 cards so MAX_CARDS is 100.
The thing is, there are only 10 unique cards. Each has their own name and their own size. Sizes like 2x6, 3x1, 4x2, 1x10, 8x4, 1x5, 6x2, etc...
The rule is that no card is bigger than the card below it. Sorted in a way of 'smallest' to largest. For example if card1 is 4x8 and card2 is 2x9, then these cards are unstackable, so they would get sorted to the end of the array, as it is possible for the next card drawn to be a card that could satisfy one of those cards and then be shuffled to the correct location in the array, same with cards with identical sizes for x and y, so repeats to the back. However, if card1 is 1x2 and card2 is 1x3 this can work and is stackable.
I hope that explain the logic of stackable cards, because that is the part i think im having trouble with.
template <typename T>
void sortArray(T c[], const int size) {
int positionOfMin, x1, x2, y1, y2;
T minValue, temp;
bool swap = false;
for (int i = 0; i < size; i++) {
minValue = c[i];
positionOfMin = i;
for (int j = i+1; j < size; j++) {
x1 = minValue.x;
y1 = minValue.y;
x2 = c[j].x;
y2 = c[j].y;
if(x1 < x2 && y1 < y2) {
swap = false;
}else if (((x1 > x2 && x1 > y2) || (y2 > x2 && y1 > y2)) ) {
swap = true;
}else if (x1 == x2 && y1 == y2){
swap = false;
}else{
swap = true;
}
if (swap == true) {
minValue = c[j];
positionOfMin = j;
}
}
// Swap the values to the new or same minimum value
temp = c[i];
c[i] = minValue;
c[positionOfMin] = temp;
}
}
Any ideas or help would be greatly appreciated, the results im getting are not correct at all.
Sort by (decreasing) {x, y}, they create a different stack once you encounter an unstackable card.
std::vector<std::vector<Card>> reorganize(std::vector<Card> cards)
{
std::sort(cards.begin(), cards.end(),
[](const Card& lhs, const Card& rhs){
return std::tie(rhs.width, rhs.height) < std::tie(lhs.width, lhs.height);
});
std::vector<std::vector<Card>> res;
for (const auto& card : cards) {
auto it = std::find_if(res.begin(), res.end(),
[&](const auto& stack) {
return card.height <= stack.back().height;
});
if (it == res.end()) {
res.push_back({card});
} else {
(*it).push_back(card);
}
}
return res;
}
Demo
Related
The problem:
Given a 2D matrix consist of 0 and 1, you can only go in location with 1. Start at point (x, y), we can move to 4 adjacent points: up, down, left, right; which are: (x+1, y), (x-1, y), (x, y+1), (x, y-1).
Find a path from point (x, y) to point (s, t) so that it has the least number of turns.
My question:
I tried to solve this problem using dijsktra, it got most of the cases right, but in some cases, it didn't give the most optimal answer.
Here's my code:
pair<int,int> go[4] = {{-1,0}, {0,1}, {1,0}, {0,-1}};
bool minimize(int &x, const int &y){
if(x > y){
x = y;
return true;
}return false;
}
struct Node{
pair<int,int> point;
int turn, direc;
Node(pii _point, int _turn, int _direc){
point = _point;
turn = _turn;
direc = _direc;
}
bool operator < (const Node &x) const{
return turn > x.turn;
}
};
void dijkstra(){
memset(turns, 0x3f, sizeof turns);
turns[xHome][yHome] = -1;
priority_queue<Node> pq;
pq.push(Node({xHome, yHome}, -1, -1));
while(!pq.empty()){
while(!pq.empty() &&
pq.top().turn > turns[pq.top().point.first][pq.top().point.second])pq.pop();
if(pq.empty())break;
pii point = pq.top().point;
int direc = pq.top().direc;
pq.pop();
for(int i = 0; i < 4; i++){
int x = point.first + go[i].first ;
int y = point.second + go[i].second;
if(!x || x > row || !y || y > col)continue;
if(matrix[x][y])
if(minimize(turns[x][y], turns[point.first ][point.second] + (i != direc)))
pq.push(Node({x, y}, turns[x][y], i));
}
}
}
P/S: The main solving is in void dijkstra, the others are just to give some more information in case you guys need it.
I have found a way to solve this problem, storing directions and using BFS() to reduce the time complexity:
struct Node{
short row, col;
char dir;
Node(int _row = 0, int _col = 0, int _dir = 0){
row = _row; col = _col; dir = _dir;
}
};
void BFS(){
memset(turns, 0x3f, sizeof turns);
deque<pair<int, Node> > dq;
for(int i = 0; i < 4; i++){
Node s(xHome + dx[i], yHome + dy[i], i);
if(!matrix[s.row][s.col])continue;
turns[s.row][s.col][s.dir] = 0;
dq.push_back({0, s});
}
while(!dq.empty()){
int d = dq.front().fi;
Node u = dq.front().se;
dq.pop_front();
if(d != turns[u.row][u.col][u.dir])continue;
for(int i = 0; i < 4; i++){
Node v(u.row + dx[i], u.col + dy[i], i);
if(!matrix[v.row][v.col])continue;
if(minimize(turns[v.row][v.col][v.dir], turns[u.row][u.col][u.dir] + (i != u.dir))){
if(i == u.dir)dq.push_front({turns[v.row][v.col][v.dir], v});
else dq.push_back({turns[v.row][v.col][v.dir], v});
trace[v.row][v.col][v.dir] = u;
}
}
}
}
An obvious error in you algorithm is that to detect the length of the path start->x->y, you should store all directions to x that can form a shortest path from start to x.
For example, suppose start=(0,0),x=(1,1),y=(1,2) and there are two paths from start to x: start->(0,1)->x, start->(1,0)->x, both have the shortest length. However, start->(0,1)->x->y has two turns while start->(1,0)->x->y has only one turn. So you need to store all the directions for each node (in this case, you should store both the directions (0,1)->x and (1,0)->x in x.
I'm building Space Invaders in C++ (using the MBed platform) for a microcontroller. I've used a 2D Vector of object pointers to organise the invaders.
The movement algorithm is below, and runs in the main while loop for the game. Basically, I get the highest/lowest x and y values of invaders in the vector, and use those to set bounds based on screensize (the HEIGHT variable);
I also get the first invader's position, velocity, and width, which I apply changes to based on the bounds above.
Then I iterate through the whole vector again and apply all those changes. It sort of works – the invaders move – but the bounds don't seem to take effect, and so they fly off screen. I feel like I'm missing something really dumb, thanks in advance!
void Army::move_army() {
int maxy = HEIGHT - 20;
int Ymost = 0; // BOTTOM
int Yleast = 100; // TOP
int Xmost = 0; // LEFT
int Xleast = 100; // RIGHT
int first_row = _rows;
int first_column = _columns;
int firstWidth = 0;
Vector2D firstPos;
Vector2D firstVel;
for (int i = 0; i < _rows; i++) {
for (int n = 0; n < _columns; n++) {
bool state = invaders[i][n]->get_death();
if (!state) {
if (i < first_row && n < first_column) {
firstPos = invaders[i][n]->get_pos();
firstVel = invaders[i][n]->get_velocity();
firstWidth = invaders[i][n]->get_width();
}
Vector2D pos = invaders[i][n]->get_pos();
if (pos.y > Ymost) {Ymost = pos.y;} // BOTTOM
else if (pos.y < Yleast) {Yleast = pos.y;} // TOP
else if (pos.x > Xmost) {Xmost = pos.x;} // LEFT
else if (pos.x < Xleast) {Xleast = pos.x;} // RIGHT
}
}
}
firstVel.y = 0;
if (Xmost >= (WIDTH - 8) || Xleast <= 2) {
firstVel.x = -firstVel.x;
firstPos.y += _inc;
// reverse x velocity
// increment y position
}
else if (Ymost > maxy) {
_inc = -_inc;
// reverse increment
}
else if (Yleast < 2) {
_inc = -_inc;
// reverse increment
}
for (int i = 0; i < _rows; i++) {
int setx = firstPos.x;
if (i > 0) {firstPos.y += 9;}
for (int n = 0; n < _columns; n++) {
invaders[i][n]->set_velocity(firstVel);
invaders[i][n]->set_pos(setx,firstPos.y);
setx += firstWidth + 2;
}
}
It looks like you have your assignment cases reversed. Assignment always goes: right <- left, so in the first case you're changing the YMost value, not pos.y. It looks like if you swap those four assignments in your bounds checking it should work. Good luck!
I have written a compare-function that should compare two possible move options for a player in a game that works like Chess. Each Move contains a Figure that should do the move and a Point, where it will move. The Points are already checked, so all of them are valid moves. When I try to sort a list containing all of the moves currently available using strict weak ordering and the std::sort function, I get a SIGSEG after my compare function got confrontet with some garbage Figure Pointer in one Move.
I already tried to figure out where the garbage pointer came from, but ony found, that the std::sort function somehow put it in the mix of all the other moves. The same seg fault occurs when i try to sort with std::stable_sort. I also thougt about stack issues due to the fact, that I had some before, but this isn't the case either.
bool cmpWhite(White_Move m1, White_Move m2) {
if (m1.f == nullptr) {
return true;
} else if (m2.f == nullptr) {
return true;
}
int sum1 = 0;
double avg1 = 0;
Figure *f1 = m1.f;
Point origin1 = f1->getCoordinatesAsPoint();
int sum2 = 0;
double avg2 = 0;
Figure *f2 = m2.f;
Point origin2 = f2->getCoordinatesAsPoint();
Point p;
movePiece(field_pub, f1, m1.p);
std::vector<Point> moves = black_king->getAllNewPossiblePositions();
for (int i = 0; i < moves.size(); i++) {
p = moves[i];
if (!black_king->isPositionBlocked(field_pub, p.x, p.y)) {
sum1++;
// avg1 += sqrt((p.x - target_pub.x) * (p.x - target_pub.x) + (p.y - target_pub.y) * (p.y - target_pub.y));
}
}
p = black_king->getCoordinatesAsPoint();
if (!black_king->isPositionBlocked(field_pub, p.x, p.y)) {
sum1++;
}
// avg1 = (double)sum1;
movePiece(field_pub, f1, origin1);
movePiece(field_pub, f2, m2.p);
moves = black_king->getAllNewPossiblePositions();
for (int i = 0; i < moves.size(); i++) {
p = moves[i];
if (!black_king->isPositionBlocked(field_pub, p.x, p.y)) {
sum2++;
// avg2 += sqrt((p.x - target_pub.x) * (p.x - target_pub.x) + (p.y - target_pub.y) * (p.y - target_pub.y));
}
}
p = black_king->getCoordinatesAsPoint();
if (!black_king->isPositionBlocked(field_pub, p.x, p.y)) {
sum2++;
}
// avg2 = (double)sum2;
movePiece(field_pub, f2, origin2);
std::cout << "cmp: " << sum1 << " " << sum2 << std::endl;
return sum1 < sum2;
}
std::vector<White_Move> sortBestMovesForWhite(Figure **figures, int size, King *bKing, int **field, Point target) {
target_pub = target;
field_pub = new int *[FIELD_WIDTH];
for (int x = 0; x < FIELD_WIDTH; x++) {
field_pub[x] = new int[FIELD_HEIGHT];
for (int y = 0; y < FIELD_HEIGHT; y++) {
field_pub[x][y] = field[x][y];
}
}
black_king = bKing;
std::vector<White_Move> moves;
for (int i = 0; i < size; i++) {
Figure *f = figures[i];
std::vector<Point> m_point = f->getAllNewPossiblePositions();
for (int j = 0; j < m_point.size(); j++) {
if (!f->isPositionBlocked(field, m_point.at(j).x, m_point.at(j).y)) {
White_Move move = {f, m_point.at(j)};
moves.push_back(move);
}
}
}
// std::stable_sort(moves.begin(), moves.end(), cmpWhite);
std::sort(moves.begin(), moves.end(), cmpWhite);
for (int x = 0; x < FIELD_WIDTH; x++) {
delete[] field_pub[x];
}
delete[] field_pub;
return moves;
}
One of your return true at the start of your compare function should be return false. The comparator for std::sort must meet the conditions specified here: https://en.cppreference.com/w/cpp/named_req/Compare. If this is not the case std::sort will have undefined behaviour.
The correct implementation should look something like:
bool cmpWhite(White_Move m1, White_Move m2) {
if (m1.f == nullptr) {
return m2.f != nullptr;
}
if (m2.f == nullptr) {
return false;
}
...
}
I'm making a 2D game in c++ and am trying to shoot enemies. When a bullet collides with the first enemy rendered then the enemy is killed fine, and it is removed from the enemys vector. However after the first enemy has been killed, other enemies no longer die.
This is where the check is carried out in the update function.
size = enemys.size();
for (int i = 0; i<size; i++)
{
double x = enemys[i].getEnemyX();
double y = enemys[i].getEnemyY();
bool isShot = enemyShot(x,y);
if(isShot == true){
enemys.erase(enemys.begin()+i);
size = size - 1;
}
}
This is the enemyShot function.
bool GameActivity::enemyShot(double enemyX, double enemyY)
{
int size = bullets.size();
for (int i = 0; i<size; i++)
{
double x = bullets[i].getX();
double y = bullets[i].getY();
if (x >= enemyX-5.0 && x <= enemyX+5.0 && y >= enemyY-5.0 && y <= enemyY + 5.0){
return true;
}
else{
return false;
}
}
}
The problem is that your vector of enemies is updated after each erasure - thus, the current index is no longer correct.
A better way to iterate the enemys vector is to start from the end of the enemys vector. That way, when you erase an element, the index is still correct:
for (size_t i = enemys.end (); i> 0; --i) {
double x = enemys[i].getEnemyX();
double y = enemys[i].getEnemyY();
bool isShot = enemyShot(x,y);
if(isShot == true){
enemys.erase(enemys.begin()+i);
}
}
I am trying to speed up a piece of code that is ran a total of 150,000,000 times.
I have analysed it using "Very Sleepy", which has indicated that the code is spending the most time in these 3 areas, shown in the image:
The code is as follows:
double nonLocalAtPixel(int ymax, int xmax, int y, int x , vector<nodeStructure> &nodeMST, int squareDimension, Mat &inputImage) {
vector<double> nodeWeights(8,0);
vector<double> nodeIntensities(8,0);
bool allZeroWeights = true;
int numberEitherside = (squareDimension - 1) / 2;
int index = 0;
for (int j = y - numberEitherside; j < y + numberEitherside + 1; j++) {
for (int i = x - numberEitherside; i < x + numberEitherside + 1; i++) {
// out of range or the centre pixel
if (j<0 || i<0 || j>ymax || i>xmax || (j == y && i == x)) {
index++;
continue;
}
else {
int centreNodeIndex = y*(xmax+1) + x;
int thisNodeIndex = j*(xmax+1) + i;
// add to intensity list
Scalar pixelIntensityScalar = inputImage.at<uchar>(j, i);
nodeIntensities[index] = ((double)*pixelIntensityScalar.val);
// find weight from p to q
float weight = findWeight(nodeMST, thisNodeIndex, centreNodeIndex);
if (weight!=0 && allZeroWeights) {
allZeroWeights = false;
}
nodeWeights[index] = (weight);
index++;
}
}
}
// find min b
int minb = -1;
int bCost = -1;
if (allZeroWeights) {
return 0;
}
else {
// iteratate all b values
for (int i = 0; i < nodeWeights.size(); i++) {
if (nodeWeights[i]==0) {
continue;
}
double thisbCost = nonLocalWithb(nodeIntensities[i], nodeIntensities, nodeWeights);
if (bCost<0 || thisbCost<bCost) {
bCost = thisbCost;
minb = nodeIntensities[i];
}
}
}
return minb;
}
Firstly, I assume the spent time indicated by Very Sleepy means that the majority of time is spent allocating the vector and deleting the vector?
Secondly, are there any suggestions to speed this code up?
Thanks
use std::array
reuse the vectors by passing it as an argument of the function or a global variable if possible (not aware of the structure of the code so I need more infos)
allocate one 16 vector size instead of two vectors of size 8. Will make your memory less fragmented
use parallelism if findWeight is thread safe (you need to provide more details on that too)