Backtracking algorithm for cell connections in a grid - c++

The explanation might be confusing or long (or both), so please let me know if there needs to be any clarification.
I am currently designing a backtracking algorithm to find a solution for something similar to what a game of "snake" looks like.
The program will start with a 2D grid, where some of the cells are inaccessible (like an obstacle). The program then proceeds with a backtracking algorithm to connect int x sequence of cells into a string-like group, then repeats this process until all int y accessible cells in the grid are connected into y / x groups. There are no cases where y is indivisible by x.
To determine the cost of the group, there are certain priority on the direction of the connection. For simplification, I will only use 3 connection types, double horizontal, double vertical, and double diagonal, where horizontal has the lowest cost and diagonal has the highest.
I've spent numerous days on trying to come up with different backtracking algorithms, but none of them had worked so far.
Here's a rough sketch of what I have(actual code has lots of custom class involved, so it may cause a lot of confusions):
String_c Grid::backtracking(int x, int y, int tot_pnl_needed, String_c &str_orig){
bool branch_found = false;
String_c str_cur = str_orig;
// set cell (x,y) as occupied. OCCUPIED is an enum value
set_avail(x,y,OCCUPIED);
str_cur.push_cell(x,y);
if (str_cur.is_complete()) {
return str_cur;
}
String_c str_tmp;
std::priority_queue<String_c, std::vector<String_c>, compareString> queue;
// if the neighboring cell is available, create a branch
if (is_available(x+1, y)){ // right side
tmp_str = backtracking(x+1, y, tot_pnl_needed-1, str_cur);
if (tmp_str == failed){ // assume that "failed" is a special String_c object. == operator is overloaded.
set_avail(x+1,y,AVAILABLE); // AVAIL is an enum value
tmp_str.pop_cell();
}
else{
branch_found = true;
queue.push(&tmp_str);
}
}
// copy this selection code above for each different direction
if (branch_found) {
while (!queue.empty()) {
// push all branches into the stack, which is a parameter of Grid class
stack.push(queue.pop());
}
else return failed;
return stack.top();
This is a pseudo code for the minimum backtracking algorithm required. In actual program, if the algorithm hits branch_found == false at the end, it needs to flip the sequence of the String_c, then continue the backtracking until it finds no branch again. Again, after one backtracking algorithm is finished, it will be called again until all cells are occupied.
One thing to be noted is that even if a String_c is completed and is pushed to the stack, it may be reverted later if none of its branch had found a solution.
This is the first time attempting to program a backtracking algorithm, so it was really stressful even to come up with this (which still fails...)
If you are the expert at this matter, I would greatly appreciate your help.

Related

Minimum Window Substring

I'm working on the Leetcode "Minimum Window Substring" practice problem:
Given two strings s and t of lengths m and n respectively, return the minimum window substring of s such that every character in t (including duplicates) is included in the window. If there is no such substring, return the empty string "".
The testcases will be generated such that the answer is unique.
Example 1:
Input: s = "ADOBECODEBANC", t = "ABC"
Output: "BANC"
Example 2:
Input: s = "a", t = "a"
Output: "a"
Example 3:
Input: s = "a", t = "aa"
Output: ""
Explanation: Both 'a's from t must be included in the window. Since the largest window of s only has one 'a', return empty string.
My solution uses two maps to keep track of character counts:
strr map is to keep count of characters in the window and
patt map is for the given pattern string.
It also uses two indices, start and end, to keep track of the current window (which includes end).
The core of the solution is an outer loop that advances end, adding the new character to strr. It then runs an inner loop as long as the window is valid that:
checks & updates the shortest window seen so far
removes the first character in the window
advances start.
Once the outer loop finishes, the shortest window it encountered should be the answer.
#include <iostream>
#include <unordered_map>
bool check_map(std::unordered_map<char, int> patt, std::unordered_map<char, int> strr)
{
for(auto data:patt)
{
if(strr[data.first] != data.second)
return false;
}
return true;
}
std::string Substring(std::string s, std::string t)
{
std::unordered_map<char, int> patt;
std::unordered_map<char, int> strr;
std::string ans;
for(int i=0; i<t.length(); i++)
patt[t[i]]++;
int start = 0, length = INT_MAX;;
for(int end=0; end<s.length(); end++)
{
strr[s[end]]++;
while(check_map(patt, strr))
{
if(length > (end-start+1))
{
ans = s.substr(start, end+1);
length = end-start+1;
}
strr[s[start]]--;
if(strr[s[start]] == 0)
strr.erase(s[start]);
start++;
}
}
return ans;
}
int main()
{
std::string s = "ADOBECODEBANC",
pattern = "ABC";
std::cout << "String: " << s << std::endl
<< "Pattern: " << pattern << std::endl
<< "Minimum Window Substring is " << Substring(s, pattern) << std::endl;
return 0;
}
For example 1 from the problem, the program should return "BANC" but instead returns "ADOBEC". Program output:
String: ADOBECODEBANC
Pattern: ABC
Minimum Window Substring is ADOBEC
Where is the error in my code?
I am very sorry that I cannot answer your concrete question to “where is the error in my code”.
But what I can do, is to help you to understand the problem, develop an algorithm and show, one of many, potential solution.
The title of the question already implies, what algorithm shall be used: The so called “Sliding Window”-algorithm.
You will find a very good explanation from Said Sryheni here.
And for your problem, we will use the Flexible-Size Sliding window approach.
We will iterate over the source string character by character and wait, until we meet a certain condition. In this case, until we “saw” all characters that needs to be searched for. Then, we will find a window, in which all these characters are.
In the given example, the end of the sliding window is always the last read character from the source string. This, because the last read character fulfills the condition. Then we need to find the beginning of the window. In that case the position of the rightmost character (of the search characters) in the source string that still fulfills the condition.
Then we will continue to read the source string and wait for the next condition to be fulfilled. And then we will recalculate the sliding window positions.
By the way. The other characters, besides the search characters in the source string, are just noise and will only extend the width of the sliding window.
But how do we meet the condition?
And especially, since the order of the search characters does not matter, and, there can even be double characters in it?
The solution is that we will “count”.
First, we will count the occurrence of all characters in the search string. Additionally, we will use a second counter that indicates if all characters are matched.
Then, while iterating over the source string, we will decrement a counter for any character that we see. If the count of a search character hits the 0, then we will decrement the “Match” counter. And, if that is 0, we found all search characters and the condition is fulfilled. We can then come to the calculation of the window positions.
Please note: We will only decrement the match counter, if, after decrementing the character counter, this will be 0.
Example (I will omit the noise with the ‘x’es):
Search string “ABC”, source string: “xxAxxxxBBBxCAxx”.
Initial character counters will be 1,1,1, the match counter will be 3.
Reading the first ‘A’. Counters: 0,1,1  2
Reading the first ‘B’. Counters: 0,0,1  1
Reading the 2nd ‘B’. Counters: 0,-1,1  1 (We will decrement the match counter only if character counter hits the 0).
Reading the 3rd ‘B’. Counters: 0,-2,1  1 (We will decrement the match counter only if character counter hits the 0).
Reading the first ‘C’. Counters: 0,-2,0  0. The match counter is 0, the condition is fulfilled.
Please note. Negative character counts indicate that there are more of the same character further right.
Next, since the condition is fulfilled now, we will check the positions of the sliding window. The end position is clear. This is the last read character from the source string. This led to the fulfillment of the condition. So, easy.
To get the start position of the sliding window, we will check from the beginning of the source string, where we can find a search character. We will increment its count, and if the count is greater then 0, we will again increment the match count. If the match count is greater than 0, we found a start position. Counters now: 1,-2,0  1
The start position will be incremented for the next check. We will never start again with 0, but only with the last used start position.
OK, having found a start and end position, we have our first window and will look for potential smaller windows. We will continue to read the source string and check
After the calculation of the sliding window position, the counter will be: 1,-2,0  1
Reading the next ‘A’. Counters: 0,-2,0  0. Again, the condition is fulfilled.
We continue with sliding window detection. The last start position was pointing to the character ‘x’ after the first ‘A’
Increment start position and skip all ‘x’es. Continue
Reading the first ‘B’. Counters: 0,-1,0  0
Reading the 2nd ‘B’. Counters: 0,0,0  0
Reading the 3d ‘B’. Counters: 0,1,0  1. Window position calculation done. Start position is the 3rd B. This window is smaller than the previous one, so take it.
Since the source string is consumed, we are done and found the solution.
How to implement that. We will do a small abstraction of the counter and pack it into a mini class. That will encapsulate the inner handling of character and match counts and can be optimized later.
A counter, which works for all kind of char types could be implemented like the below:
struct SpecialCounterForGeneralChar {
std::unordered_map<char, int> individualLetter{};
int necessaryMatches{};
SpecialCounterForGeneralChar(const std::string& searchLetters) {
for (const char c : searchLetters) individualLetter[c]++;
necessaryMatches = individualLetter.size();
}
inline void incrementFor(const char c) {
individualLetter[c]++;
if (individualLetter[c] > 0)
++necessaryMatches;
}
inline void decrementFor(const char c) {
individualLetter[c]--;
if (individualLetter[c] == 0)
--necessaryMatches;
}
inline bool allLettersMatched() { return necessaryMatches == 0; }
};
If we know more about the input data and it is for example restricted to an 8 bit char, we can also use:
struct SpecialCounter {
char individualLetter[256]{};
int necessaryMatches{};
SpecialCounter(const std::string& searchLetters) {
for (const char c : searchLetters) {
if (individualLetter[c] == 0) ++necessaryMatches;
individualLetter[c]++;
}
}
inline void incrementFor(const char c) {
individualLetter[c]++;
if (individualLetter[c] > 0)
++necessaryMatches;
}
inline void decrementFor(const char c) {
individualLetter[c]--;
if (individualLetter[c] == 0)
--necessaryMatches;
}
inline bool allLettersMatched() { return necessaryMatches == 0; }
};
This will be slightly faster than the above (under the given restrictions)
And, then the rest of the program will then be just 15 lines of code.
The important message here is that we need to think very verylong, before we start to implement the first line of code.
A good selected algorithm and design, will help us to find an optimum solution.
Please see the complete example solution below:
#include <string>
#include <iostream>
#include <unordered_map>
#include <limits>
using Index = unsigned int;
// We want to hide the implementation of the special counter to the outside world
struct SpecialCounter {
char individualLetter[256]{};
int necessaryMatches{};
SpecialCounter(const std::string& searchLetters) {
for (const char c : searchLetters) {
if (individualLetter[c] == 0) ++necessaryMatches;
individualLetter[c]++;
}
}
inline void incrementFor(const char c) {
individualLetter[c]++;
if (individualLetter[c] > 0)
++necessaryMatches;
}
inline void decrementFor(const char c) {
individualLetter[c]--;
if (individualLetter[c] == 0)
--necessaryMatches;
}
inline bool allLettersMatched() { return necessaryMatches == 0; }
};
std::string solution(std::string toBeSearchedIn, std::string toBeSearchedFor) {
// Counter with somespecial properties
SpecialCounter counter(toBeSearchedFor);
// This will be slided. End of window is always last read character. Start of window may increase
Index currentWindowStart {};
// The potential solution
Index resultingWindowStart {};
Index resultingWindowWith{ std::numeric_limits<size_t>::max() };
// Iterate over all characters of the string under evaluation
for (Index index{}; index < toBeSearchedIn.length(); ++index) {
// We saw a character. So, subtract from characters to be searched
counter.decrementFor(toBeSearchedIn[index]);
// If we hit and found all necessary characters and adjusted the sliding windows start position
while (counter.allLettersMatched()) {
// Calculate start and width of sliding window. So, if we found a new, more narrow window
const unsigned int currentWindowWith{ index - currentWindowStart + 1 };
if (currentWindowWith < resultingWindowWith) {
// Remember one potential solution
resultingWindowWith = currentWindowWith;
resultingWindowStart = currentWindowStart;
}
// Now, for the sliding window. We saw and decremented thsi character before
// Now we see it in the sliding window and increment it again.
counter.incrementFor(toBeSearchedIn[currentWindowStart]);
// Slide start of window to one to the right
currentWindowStart++;
}
}
return (resultingWindowWith != std::numeric_limits<size_t>::max()) ? toBeSearchedIn.substr(resultingWindowStart, resultingWindowWith) : "No solution";
}
int main()
{
const std::string toBeSearchedIn{ "KKKADOBECODEBBBAANCKKK" };
const std::string toBeSearchedFor = { "AABBC" };
std::cout << "Solution:\n" << solution(toBeSearchedIn, toBeSearchedFor) << '\n';
}
Since the question is part of an attempt at an exercise, this answer will not present a complete solution to the exercise problem that inspired it. Instead, it will do just what is asked: it will point out the main issue with the posted code, and how it can be discovered.
Code Examination
An artful approach is to check for mismatches between the requirements, design, and implementation; artful because this approach is more an art than a science, and you can easily lead yourself astray. This basically involves running through design and through implementation in your head, as if you were the processor, though perhaps examining only small parts of the code at a time.
Some of the implementation looks fine, such as: end advancing along in the outer loop, checking for a smaller window (and replacing the previous smallest window). Some could stand closer examination, such as removing entries from the window histogram after checking that the window is valid (for algorithm correctness, it's very useful to think of good loop invariants, such as 'the window should always be valid', and ensure they always hold true).
However, when you look at check_map, there's a mismatch. One problem requirement is:
every character in t (including duplicates) is included in the window
While there is a slight ambiguity in the phrasing (if a character from t occurs in a window more than in t, is the window valid?), the straight reading of this requirement is that the count of a character in s must be at least the count of a character in t. In check_map, the counts are being compared exactly. This strongly suggests a place to examine more closely.
Testing
A semi-automated, systematic approach that can catch all sorts of bugs is using tests, both unit and integration (a search of this site and the web at large will explain these terms). One key part of tests is identifying edge cases to test. For example, if you try with the search string "ACBA" and pattern "AB", the example program correctly finds the minimum window "BA". However, for the search string "ACBBA", it returns "ACB" as the minimum window. This suggests the implementation has an issue with character counts, which makes check_map the prime suspect (and the lines that update strr the secondary suspect).
For another test, consider search string "A123B12345A12BA123A" and pattern "AAB". This has 3 potential windows, with the shortest in the middle. If you fix check_map and test your code against this test case, the code returns "A12BA123A", rather than "A12BA". This suggests something is either wrong with testing the window validity (check_map again) or with setting the answer. Some scaffolding code (e.g. printing start, end and ans when it's updated) will reveal the cause.
Debugging
The most general approach that can reveal an issue with implementation correctness is to use an interactive debugger. For the sample code, breakpoints can be set at various key points, such as beginning of loops and branches. You can furthermore make these breakpoints conditional, at the indices when the code should be finding new windows. If you do this, you'll find that check_map returns false in instances when you'd expect it to be returning true. From there, you can start stepping in to check_map to observe why it's doing this.
Once that's fixed, there is still an issue with the code, though you'll need a test case such as the one with "A123B12345A12BA123A" above, as the issue isn't apparent with the "ADOBECODEBANC" test case. Stepping through the inner loop and examining the various variables will reveal what's going wrong.
Check the API
Bugs basically all have one cause: you expect the code to do one thing, but it does something different. One source of this is misunderstanding an API, so it can be helpful to read the API documentation to make sure your understanding is correct. Typically, before going to the API you'll want to find the specific API calls that aren't behaving as you understand them, which debugging can reveal. I mention this because there is an API call in the sample code that is incorrect.
Conclusion
Each of the above approaches leads to the same bug: the comparison in check_map. Two of them also can lead to an additional bug, given a suitable test case.
Additional Notes
Efficiency
Substring examines & tracks not only those characters in t, but all characters. This leads to the inner loop body being executed (including updating ans) for every character in s, not only those that are present in the pattern. Generally, you should make an implementation correct, then make it efficient. However, in this case it's trivial to make Substring ignore characters that aren't in the pattern and is closer to the problem description.
Types
An earlier formulation of this answer, addressing an earlier formulation of the question, covered examining types to check that they're the most appropriate. For the updated question, this no longer leads to bug discovery.
One point from the early formulation still applies to designing a solution.
Conceptually, the most appropriate data type for the pattern characters and the characters in the current window would be a multiset. As the window shifts, characters can be added and removed simply from a multiset. The validity of the current window is a simple subset operation (pattern ⊆ window). However, multiset in the STL doesn't correspond to the mathematical multiset.

Using glutTimerFunc with glutMouseFunc

I am trying to do a little game, and in my game I have some squares and when the user click on these squares, they got highlighted. To achieve this effect I am using glutMouseFunc with glutTimerFunc.
When the user clicks on the screen I pick the pixel and identify the square I need to highlight. Once the square is identified I call glutTimerFunc. The function registred with glutTimerFunc increase the value of each component of color by 0.01 until they reach one max value defined by me, then this value goes back to a minimum value.
glutTimerFunc execute in 60 milliseconds and I get a almost smooth shine effect.
My problem is, if I click on two squares very fast, the effect starts on the first square, but don't finish, so the square remains highlighted and the second squares do the entire effect. If I click like a crazy man on every square, all of them got highlighted.
How can I make this effect of shining terminate even if I click on other square?
Here is a snippet of code
void Memoria::shineEffect(GLint value) {
if(value == 1) {
for(GLint i = 0; i < 3; i++) {
if(colors[selectedSquare][i] > 0) {
colors[selectedSquare][i] += COLOR_INCREASE;
if(colors[selectedSquare][i] >= MAX) {
colors[selectedSquare][i] = MAX;
value = -1;
}
}
}
glutTimerFunc(FPS, timeWrapper, value);
}
else {
if(value == -1) {
for(GLint i = 0; i < 3; i++) {
if(colors[selectedSquare][i] > 0) {
colors[selectedSquare][i] -= COLOR_INCREASE;
if(colors[selectedSquare][i] <= MIN) {
value = 0;
colors[selectedSquare][i] = MIN;
}
}
}
glutTimerFunc(FPS, timeWrapper, value);
}
}
}
timeWrapper calls shineEffect if the value passed in the parameter is 1 or -1.
You want the shineEffect function to go through one highlight loop at least, and then stop if the highlighted item has changed. It's more a UI code design issue rather than an OpenGL or GLUT one.
The mechanic you need to implement is pretty straightforward:
install once for all an updateHighlights function with glutTimerFunc: this function will be responsible of updating the highlights of all the clicked elements,
create a queue of elements: each time an element has been clicked, add it to the queue,
The task performed by the updateHighLights function should be as follow:
if the queue contains one element, keep cycling its highlight as you already do in your program
if the queue contain more than one element, for each element in the queue,
step the highlight cycle
if the cycle is over, and the element is not the last one, remove the element from the queue
Here's another perhaps more flexible take on your problem.
The Glut event loop machinery is very simple design: there's only one hook to put your "idle work" code, so it's probably more flexible to install a function there which calls a list of others functions. That list could be then modified with a set primitive, to install or remove specific tasks to perform during idle time. This could be much more flexible than the "one function" approach of GLUT.
For instance, you could isolate your current highlight code in one function with a struct containing the element to highlight, and have the function remove itself from the list when its element is done through a highlight cycle and isn't active anymore.
Since you are using C++, it should be easy to bundle all these functionalities in classes:
one class for the list of idle tasks
one base class for idle tasks
one derived idle task class for the purpose of highlighting a square (with fields for the square and for the active status)
one class to keep track of the active square, so that it may be easily deactivated and replaced by the new active one. This one would be accessed by the glutMouseFunc function.

Killing the invaders doesn't work in C++

I know that in order to kill invaders in C++, I need to make a collider.
However, nothing will ever kill the invaders in that game.
Here's the code in the header:
bool DoCollision(float Xbpos, float Ybpos, int BulWidth, int BulHeight, float Xipos, float Yipos, int InvWidth, int InvHeight);
This is the function I'm initializing:
bool Game::DoCollision(float Xbpos, float Ybpos, int BulWidth, int BulHeight, float Xipos, float Yipos, int InvWidth, int InvHeight) {
if (Xbpos+BulWidth < Xipos || Xbpos > Xipos+InvWidth) return false;
if (Ybpos+BulHeight < Yipos || Ybpos > Yipos+InvHeight) return false;
return true;
}
And this is what happens if somebody presses the space key:
if (code == 57) { //Space
myKeyInvader.MeBullet.Active = true;
myKeyInvader.MeBullet.Xpos = myKeyInvader.Xpos + 10;
myKeyInvader.MeBullet.Ypos = myKeyInvader.Ypos - 10;
myKeyInvader.MeBullet.yvuel = 0.2;
myKeyInvader.MeBullet.BulletP->CopyTo(m_Screen,myKeyInvader.Xpos,myKeyInvader.Ypos);
if (DoCollision(Invaders[counter].MyBullet.Xbpos,Invaders[counter].MyBullet.Ybpos,Invaders[counter].MyBullet.BulWidth,
Invaders[counter].MyBullet.BulHeight,Invaders[counter].Xipos,Invaders[counter].Yipos,Invaders[counter].InvWidth,Invaders[counter].InvHeight)) {
//myKeyInvader.Ypos = 100;
Invaders[counter].Active = false;
printf("Collide!\n");
}
}
Does anybody know what's going wrong?
The problem isn't C++. The problem is how you are using it. The only way you'll get a kill with your code as written is if the invader is right on top of you. But that's too late. The alien invader has already killed you.
What you need to do is make those bullets into objects that you propagate over time, just like your invaders are objects that you propagate over time. The response to the user pressing a space key should be to add a new instance of a bullet to the set of active bullets. Each of those active bullets has a position that changes with time. On each time step, you should advance the states of the active invaders per the rules that dictate how invaders move and advance the states of the active bullets per the rules that dictate how bullets move. Remove bullets when they reach the top of the screen, and if an alien invader reaches the bottom of the screen, game over.
After propagating, removing off-screen bullets, and checking for game over, you want to check for collisions between each of the N bullets with each of the M invaders. When a collision is detected, remove the bullet from the set of active bullets and delete the alien invader from the set of active invaders. And of course you'll want some nifty graphics to show the user that another alien bit the dust.
Aside: Being an NxM problem, this check might be the biggest drain on CPU usage. You can speed this up with some simple heuristics.
You could manage the collections of alien invaders and bullets yourself, carefully using new and delete so as to prevent your invaders and bullets from killing your program with a memory leak. You don't have to do this. C++ gives you some nifty tools to manage these collections. Use one of the C++ standard library collections instead of rolling your own collection. For example, std::vector<AlienInvader> invaders; or std::list<AlienInvader> invaders, and the same for bullets. You'll be deleting from the middle a lot, which suggests that std::list or std::deque might be more appropriate than std::vector here.
You test the collision for the fired item just when they are created
Shouldn't be the test collision done in the main loop for each existing item at each frame ?
Don't worry, C++ has got all you need to kill invaders :)))
It's not easy to give advice based on so little code, but here the only logical error seems to be you test for collision only when space is pressed; you should test for it in an outside loop probably:
if (code == 57) { //Space
myKeyInvader.MeBullet.Active = true;
myKeyInvader.MeBullet.Xpos = myKeyInvader.Xpos + 10;
myKeyInvader.MeBullet.Ypos = myKeyInvader.Ypos - 10;
myKeyInvader.MeBullet.yvuel = 0.2;
myKeyInvader.MeBullet.BulletP->CopyTo(m_Screen,myKeyInvader.Xpos,myKeyInvader.Ypos);
}
From a logical point of view, pressing Space should fire a bullet: the starting position for the bullet is set, and so is its speed on the Y axis (so that it goes up).
The code that check for collision should go outside of this if block. In fact, this block of code is executed only if you're still pressing space -that is: still firing-. Should collision be checked only if you're "still firing"? Do the fact that you fired a bullet and started waiting for it to destroy the invader interfere in some way with the fact that this bullet can reach the invader and, indeed, destroy it? Of course not!
if (DoCollision(Invaders[counter].MyBullet.Xbpos,Invaders[counter].MyBullet.Ybpos,Invaders[counter].MyBullet.BulWidth,
Invaders[counter].MyBullet.BulHeight,Invaders[counter].Xipos,Invaders[counter].Yipos,Invaders[counter].InvWidth,Invaders[counter].InvHeight)) {
//myKeyInvader.Ypos = 100;
Invaders[counter].Active = false;
printf("Collide!\n");
}
You want collision to be checked in an outside loop, the same that probably also contains the checks for key presses. In this way, even if you're just looking at the screen and waiting, the program keeps testing the condition and, when it's fulfilled, code associated with the event of collision is executed (that is: an invader is "inactivated").
You say //Space , is that what it is or should it be 32 (if ASCII) instead of 57? Does the program flow into the if==57 block?
Your code looks fine, but you need two loops around the collision checker: one for checking all invaders (not just one of them) and another one to check at every bullet position along its trajectory, not just the moment when it leaves the gun.
I will assume we have an auxiliary function that moves the bullet and returns whether it is still inside the screen:
bool BulletIsInScreen();
Then we can write the loops:
if (code == 57) { // Space
while (BulletIsInScreen()) {
for (size_t i = 0; i < counter; ++i) { // counter is the number of invaders,
// according to your comment to your own answer
myKeyInvader.MeBullet.Active = true;
myKeyInvader.MeBullet.Xpos = myKeyInvader.Xpos + 10;
myKeyInvader.MeBullet.Ypos = myKeyInvader.Ypos - 10;
myKeyInvader.MeBullet.yvuel = 0.2;
myKeyInvader.MeBullet.BulletP->CopyTo(m_Screen,myKeyInvader.Xpos,myKeyInvader.Ypos);
if (DoCollision(Invaders[i].MyBullet.Xbpos, Invaders[i].MyBullet.Ybpos,
Invaders[i].MyBullet.BulWidth, Invaders[i].MyBullet.BulHeight,
Invaders[i].Xipos, Invaders[i].Yipos,
Invaders[i].InvWidth, Invaders[i].InvHeight)) {
//myKeyInvader.Ypos = 100;
Invaders[i].Active = false;
printf("Collide!\n");
}
}
}
}
Now this should work as expected.

A* pathfinding slow

I am currently working on a A* search algorithm. The algorithm would just be solving text file mazes. I know that the A* algorithm is supposed to be very quick in finding the finish. Mine seems to take 6 seconds to find the path in a 20x20 maze with no walls. It does find the finish with the correct path it just takes forever to do so.
If I knew which part of code was the problem I would just post that but I really have no idea what is going wrong. So here is the algorithm that I use...
while(!openList.empty()) {
visitedList.push_back(openList[index]);
openList.erase(openList.begin() + index);
if(currentCell->x_coor == goalCell->x_coor && currentCell->y_coor == goalCell->y_coor)
}
FindBestPath(currentCell);
break;
}
if(map[currentCell->x_coor+1][currentCell->y_coor] != wall)
{
openList.push_back(new SearchCell(currentCell->x_coor+1,currentCell->y_coor,currentCell));
}
if(map[currentCell->x_coor-1][currentCell->y_coor] != wall)
{
openList.push_back(new SearchCell(currentCell->x_coor-1,currentCell->y_coor,currentCell));
}
if(map[currentCell->x_coor][currentCell->y_coor+1] != wall)
{
openList.push_back(new SearchCell(currentCell->x_coor,currentCell->y_coor+1,currentCell));
}
if(map[currentCell->x_coor][currentCell->y_coor-1] != wall)
{
openList.push_back(new SearchCell(currentCell->x_coor,currentCell->y_coor-1,currentCell));
}
for(int i=0;i<openList.size();i++) {
openList[i]->G = openList[i]->parent->G + 1;
openList[i]->H = openList[i]->ManHattenDistance(goalCell);
}
float bestF = 999999;
index = -1;
for(int i=0;i<openList.size();i++) {
if(openList[i]->GetF() < bestF) {
for(int n=0;n<visitedList.size();n++) {
if(CheckVisited(openList[i])) {
bestF = openList[i]->GetF();
index = i;
}
}
}
}
if(index >= 0) {
currentCell = openList[index];
}
}
I know this code is messy and not the most efficient way to do things but I think it should still be faster then what it is. Any help would be greatly appreciated.
Thanks.
Your 20x20 maze has no walls, and therefore many, many routes which are all the same length. I'd estimate trillions of equivalent routes, in fact. It doesn't seem so bad when you take that into account.
Of course, since your heuristic looks perfect, you should get a big benefit from excluding routes that are heuristically predicted to be precisely as long as the best route known so far. (This is safe if your heuristic is correct, i.e. never overestimates the remaining distance).
Here is a big hint.
If ever you find two paths to the same cell, you can always throw away the longer one. If there is a tie, you can throw away the second one to get there.
If you implement that, with no other optimizations, the search would become more than acceptably fast.
Secondly the A* algorithm should only bother backtracking if the length to the current cell plus the heuristic exceeds the length to the current cell plus the heuristic for any other node. If you implement that, then it should directly find a path and stop. To facilitate that you need to store paths in a priority queue (typically implemented with a heap), not a vector.
openList.erase is O(n), and the for-loop beginning with for(int i=0;i<openList.size();i++) is O(n^2) due to the call to CheckVisited - these are called every iteration, making your overall algorithm O(n^3). A* should be O(n log n).
Try changing openList to a priority-queue like it's supposed to be, and visitedList to a hash table. The entire for loop can then be replaced by a dequeue - make sure you check if visitedList.Contains(node) before enqueuing!
Also, there is no need to recalculate the ManHattenDistance for every node every iteration, since it never changes.
Aren't you constantly backtracking?
The A* algorithm backtracks when the current best solution becomes worse than another previously visited route. In your case, since there are no walls, all routes are good and never die (and as MSalters correctly pointed, there are several of them). When you take a step, your route becomes worse than all the others that are one step shorter.
If that is true, this may account for the time taken by your algorithm.

Optimizing C++ Tree Generation

I'm generating a Tic-Tac-Toe game tree (9 seconds after the first move), and I'm told it should take only a few milliseconds. So I'm trying to optimize it, I ran it through CodeAnalyst and these are the top 5 calls being made (I used bitsets to represent the Tic-Tac-Toe board):
std::_Iterator_base::_Orphan_me
std::bitset<9>::test
std::_Iterator_base::_Adopt
std::bitset<9>::reference::operator bool
std::_Iterator_base::~_Iterator_base
void BuildTreeToDepth(Node &nNode, const int& nextPlayer, int depth)
{
if (depth > 0)
{
//Calculate gameboard states
int evalBoard = nNode.m_board.CalculateBoardState();
bool isFinished = nNode.m_board.isFinished();
if (isFinished || (nNode.m_board.isWinner() > 0))
{
nNode.m_winCount = evalBoard;
}
else
{
Ticboard tBoard = nNode.m_board;
do
{
int validMove = tBoard.FirstValidMove();
if (validMove != -1)
{
Node f;
Ticboard tempBoard = nNode.m_board;
tempBoard.Move(validMove, nextPlayer);
tBoard.Move(validMove, nextPlayer);
f.m_board = tempBoard;
f.m_winCount = 0;
f.m_Move = validMove;
int currPlay = (nextPlayer == 1 ? 2 : 1);
BuildTreeToDepth(f,currPlay, depth - 1);
nNode.m_winCount += f.m_board.CalculateBoardState();
nNode.m_branches.push_back(f);
}
else
{
break;
}
}while(true);
}
}
}
Where should I be looking to optimize it? How should I optimize these 5 calls (I don't recognize them=.
The tic-tac-toe game tree is very redundant. Eliminating rotated and mirrored boards will reduce the final ply of the game tree by 3 or 4 orders of magnitude. No amount of optimizations will make bubblesort as fast as introsort.
struct Game_board;
struct Node
{
Game_board game_board;
Node* parent;
std::vector<Node*> children;
enum { X_Win, Y_Win, Draw, Playing } outcome;
};
// returns the same hash value for all "identical" boards.
// ie boards that can be rotated or mirrored to look the
// same will have the same hash value
int hash( const Game_board& game_board );
// uses hash() function to generate hashes from Node*
struct Hash_functor;
// nodes yet to be explored.
std::hash_set<Node*,Hash_functor> open;
//nodes already explored.
std::hash_set<Node*,Hash_functor> closed;
while( ! open.empty() )
{
Node* node_to_expore = get_a_node( open );
assert( node_to_expore not in close or open sets )
if( node_to_expore is win lose or draw )
{
Mark node as win lose or draw
add node to closed set
}
loop through all children of node_to_expore
{
if( child in close )
{
add node from closed set to children list of node_to_expore
}
else if( child in open )
{
add node from open set to children list of node_to_explore
}
else
{
add child to open set
add child to children list of node_to_expore
}
}
}
Those functions are typically trivial. That means that an optimized ("release") build will typically have them inlined. However, in a debug build they're not. The result is that a debug build is slower, but allows you to set breakpoints on those functions. So, the "milliseconds comment" should be applied to the release build, where you wouldn't even have those functions anymore.
You're getting all wrapped up in data structure.
Don't build the tree, just walk it. Have only one copy of the board. At each node in the search tree, just modify the board, and on the way back out, un-modify it.
And if you want to know what it's doing, just hit the pause button at random. It will show you why it's in those routines you don't recognize that are taking all the time.
Honestly, and I don't mean this as a slam against you, you're asking us to examine a poorly documented piece of code that is a smaller part to a larger code base. We don't have the context that gives much information. I personally am also turned off by examining others' code when it doesn't appear that they've done all they can do to examine it themselves yet (and I don't mean this to say I'm annoyed at you or anything, just that my eyes are glazing over looking at your code).
I recommend you run your code through a profiler and determine what exactly is taking so much time. Treat this profiling like you're debugging. When you find a module taking a long time, examine that module in small sections (as if you're hunting for a bug) to see why.
This will allow you to ask a much more informed question if you still need to ask something.
You've posted far too little of your code.
You are asking how to optimize the code however you should also be asking how to optimize the algorithm.
There are two things that I immediately see.
As "Michael Dorgan" stated generate the tree of moves once.
How many broads are you generating in your tree? 362880? Your code appears to be generating redundant entries. For example, with an empty board there are actually three moves not nine moves. All other combinations are the board rotated (which are equal). You can reduce the number of boards that needs to be generated and speed up the generation of the tree.
Here are the three first moves(rotate the last two board to generate the other boards)
| |
|X|
| |
|X|
| |
| |
X| |
| |
| |
Let me add that if your system is taking 9 seconds to do its work, that means that something is being called billions and billions of times more than it should. If you don't have release level profiling abilities, place a few global counters in your code and increment them every time the code they are in is called. This will give you a poor man's profile that will work on release builds. If you see a billions calls somewhere you don't expect, you now have a place to look closer.
In reality, Tic-Tac-Toe's entire move tree should be trivial to store as a hash if you need the speed. 9! moves just isn't that big of a domain (anymore). 362k moves shouldn't break the bank, and that's a brute force analysis. That domain can be cut way down when you take into consideration all the various symetries of data.
Bah, here's how I would do it if I was coding it since people have latched onto my back of the envelope math:
I wouldn't even go the tree route, just some rules and be done.
Turn 1. Go in center.
Turn 2. If center unoccupied, go there, else go in corner
Turn 3. If opponent filled a corner, go in opposite corner, else go in corner - you've won.
Turn 4. Block if needed. If Xs occupy opposite corners, fill edge. If Xs occupy center and opposite corner, fill corner. If Xs occupy opposite edges, fill corner and win. If Xs fill adjacent edges, Fill corner betweem them.
Turn 5 Win if possible. Block if needed. Else go in corner opposite of adjacent edge move and win.
Turn 6-9 Win if possible. Block if needed. Else, place random towards draw.