Optimising Minimax for a Game - dynamic-programming

I'm currently trying to solve a programming problem using minimax with alpha-beta-pruning.
The game is represented as a tree with a defined root. Each node has a given cost. Each node can have an amount of childs bigger than 0 if its not a leaf. The game has to end at a leaf.
Player A wants to maximize the cost he can receive by traversing the tree. He can choose to stay at the current node, or go to one of its childs.
Player B wants to minimize the cost, but he has to choose a child and can't pass unlike Player A.
Both Players play optimally.
I have implemented a solution, which does return the desired results, but is too slow after a certain amount of nodes, leading to a timeout.
My idea would be to somehow save the results of the previous minimax search for the given tree, but that only helps if Player A chooses to advance, otherwise I would have to do the minimax search again.
vector<int> edges[MAXN];
int minimax(int node, bool p1_turn, int alpha, int beta) {
if(edges[node].empty()) return cost[node];
if(p1_turn) {
int best = minimax(node, false, alpha, beta);
for(auto u: edges[node]) {
int val = minimax(u, false, alpha, beta);
best = max(val, best);
alpha = max(alpha, best);
if(beta <= alpha) {
break;
}
}
return best;
} else {
int best = MAX_INF;
for(auto u: edges[node]){
int val = minimax(u, true, alpha, beta);
best = min(best, val);
beta = min(best, beta);
if(beta <= alpha){
break;
}
}
return best;
}
}
...
minimax(1, true, MIN_INF, MAX_INF)
...
Applying the above algorithm returns the desired results, but is too slow after a certain amount of nodes.
EDIT
Changed the inner if-block to be more in line with https://en.wikipedia.org/wiki/Alpha%E2%80%93beta_pruning#Pseudocode
if(edges[node].empty()) return cost[node];
if(p1_turn) {
int best = minimax(node, false, alpha, beta);
for(auto u: edges[node]) {
best = max(best, minimax(u, false, alpha, beta));
if(best > beta) {
break;
}
alpha = max(alpha, best);
}
return best;
} else {
int best = MAX_INF;
for(auto u: edges[node]){
best = min(best, minimax(u, true, alpha, beta));
if(best < alpha){
break;
}
beta = min(best, beta);
}
return best;
}

Related

cs50 tideman lock_paiors function issue

hi guys im having problome with my lockpairs functinog on pset3 tideman would love some feedback ty
bool checkcycle(int from, int to)
{
if(from == to)
{
return true;
}
int i;
for (i = 0; i < candidate_count; i++)
{
if(locked[from][i])
{
checkcycle(i,to);
}
}
return false;
}
void lock_pairs(void)
{
for (int i = 0; i < candidate_count; i++)
{
if(!checkcycle(pairs[i].winner , pairs[i].loser))
{
locked[pairs[i].winner][pairs[i].loser] = true;
}
return;
}
}
:( lock_pairs locks all pairs when no cycles
lock_pairs did not lock all pairs
:( lock_pairs skips final pair if it creates cycle
lock_pairs did not correctly lock all non-cyclical pairs
:( lock_pairs skips middle pair if it creates a cycle
lock_pairs did not correctly lock all non-cyclical pairs
Your checkcycle function just need a little adjustment. I would change from to winner and to to loser. I think it would be easier to understand. Given a pair, you will call checkcycle(winner, loser). After checking if winner == loser, you should iterate over all pairs checking if loser is the winner, and calling checkcycle(winner, loser), passing the same original winner, and the loser of the loser

Why is the following a memory leak? [duplicate]

I've got code that looks like this:
for (std::list<item*>::iterator i=items.begin();i!=items.end();i++)
{
bool isActive = (*i)->update();
//if (!isActive)
// items.remove(*i);
//else
other_code_involving(*i);
}
items.remove_if(CheckItemNotActive);
I'd like remove inactive items immediately after update them, inorder to avoid walking the list again. But if I add the commented-out lines, I get an error when I get to i++: "List iterator not incrementable". I tried some alternates which didn't increment in the for statement, but I couldn't get anything to work.
What's the best way to remove items as you are walking a std::list?
You have to increment the iterator first (with i++) and then remove the previous element (e.g., by using the returned value from i++). You can change the code to a while loop like so:
std::list<item*>::iterator i = items.begin();
while (i != items.end())
{
bool isActive = (*i)->update();
if (!isActive)
{
items.erase(i++); // alternatively, i = items.erase(i);
}
else
{
other_code_involving(*i);
++i;
}
}
You want to do:
i= items.erase(i);
That will correctly update the iterator to point to the location after the iterator you removed.
You need to do the combination of Kristo's answer and MSN's:
// Note: Using the pre-increment operator is preferred for iterators because
// there can be a performance gain.
//
// Note: As long as you are iterating from beginning to end, without inserting
// along the way you can safely save end once; otherwise get it at the
// top of each loop.
std::list< item * >::iterator iter = items.begin();
std::list< item * >::iterator end = items.end();
while (iter != end)
{
item * pItem = *iter;
if (pItem->update() == true)
{
other_code_involving(pItem);
++iter;
}
else
{
// BTW, who is deleting pItem, a.k.a. (*iter)?
iter = items.erase(iter);
}
}
Of course, the most efficient and SuperCool® STL savy thing would be something like this:
// This implementation of update executes other_code_involving(Item *) if
// this instance needs updating.
//
// This method returns true if this still needs future updates.
//
bool Item::update(void)
{
if (m_needsUpdates == true)
{
m_needsUpdates = other_code_involving(this);
}
return (m_needsUpdates);
}
// This call does everything the previous loop did!!! (Including the fact
// that it isn't deleting the items that are erased!)
items.remove_if(std::not1(std::mem_fun(&Item::update)));
I have sumup it, here is the three method with example:
1. using while loop
list<int> lst{4, 1, 2, 3, 5};
auto it = lst.begin();
while (it != lst.end()){
if((*it % 2) == 1){
it = lst.erase(it);// erase and go to next
} else{
++it; // go to next
}
}
for(auto it:lst)cout<<it<<" ";
cout<<endl; //4 2
2. using remove_if member funtion in list:
list<int> lst{4, 1, 2, 3, 5};
lst.remove_if([](int a){return a % 2 == 1;});
for(auto it:lst)cout<<it<<" ";
cout<<endl; //4 2
3. using std::remove_if funtion combining with erase member function:
list<int> lst{4, 1, 2, 3, 5};
lst.erase(std::remove_if(lst.begin(), lst.end(), [](int a){
return a % 2 == 1;
}), lst.end());
for(auto it:lst)cout<<it<<" ";
cout<<endl; //4 2
4. using for loop , should note update the iterator:
list<int> lst{4, 1, 2, 3, 5};
for(auto it = lst.begin(); it != lst.end();++it){
if ((*it % 2) == 1){
it = lst.erase(it); erase and go to next(erase will return the next iterator)
--it; // as it will be add again in for, so we go back one step
}
}
for(auto it:lst)cout<<it<<" ";
cout<<endl; //4 2
Use std::remove_if algorithm.
Edit:
Work with collections should be like:
prepare collection.
process collection.
Life will be easier if you won't mix this steps.
std::remove_if. or list::remove_if ( if you know that you work with list and not with the TCollection )
std::for_each
The alternative for loop version to Kristo's answer.
You lose some efficiency, you go backwards and then forward again when deleting but in exchange for the extra iterator increment you can have the iterator declared in the loop scope and the code looking a bit cleaner. What to choose depends on priorities of the moment.
The answer was totally out of time, I know...
typedef std::list<item*>::iterator item_iterator;
for(item_iterator i = items.begin(); i != items.end(); ++i)
{
bool isActive = (*i)->update();
if (!isActive)
{
items.erase(i--);
}
else
{
other_code_involving(*i);
}
}
Here's an example using a for loop that iterates the list and increments or revalidates the iterator in the event of an item being removed during traversal of the list.
for(auto i = items.begin(); i != items.end();)
{
if(bool isActive = (*i)->update())
{
other_code_involving(*i);
++i;
}
else
{
i = items.erase(i);
}
}
items.remove_if(CheckItemNotActive);
Removal invalidates only the iterators that point to the elements that are removed.
So in this case after removing *i , i is invalidated and you cannot do increment on it.
What you can do is first save the iterator of element that is to be removed , then increment the iterator and then remove the saved one.
If you think of the std::list like a queue, then you can dequeue and enqueue all the items that you want to keep, but only dequeue (and not enqueue) the item you want to remove. Here's an example where I want to remove 5 from a list containing the numbers 1-10...
std::list<int> myList;
int size = myList.size(); // The size needs to be saved to iterate through the whole thing
for (int i = 0; i < size; ++i)
{
int val = myList.back()
myList.pop_back() // dequeue
if (val != 5)
{
myList.push_front(val) // enqueue if not 5
}
}
myList will now only have numbers 1-4 and 6-10.
Iterating backwards avoids the effect of erasing an element on the remaining elements to be traversed:
typedef list<item*> list_t;
for ( list_t::iterator it = items.end() ; it != items.begin() ; ) {
--it;
bool remove = <determine whether to remove>
if ( remove ) {
items.erase( it );
}
}
PS: see this, e.g., regarding backward iteration.
PS2: I did not thoroughly tested if it handles well erasing elements at the ends.
You can write
std::list<item*>::iterator i = items.begin();
while (i != items.end())
{
bool isActive = (*i)->update();
if (!isActive) {
i = items.erase(i);
} else {
other_code_involving(*i);
i++;
}
}
You can write equivalent code with std::list::remove_if, which is less verbose and more explicit
items.remove_if([] (item*i) {
bool isActive = (*i)->update();
if (!isActive)
return true;
other_code_involving(*i);
return false;
});
The std::vector::erase std::remove_if idiom should be used when items is a vector instead of a list to keep compexity at O(n) - or in case you write generic code and items might be a container with no effective way to erase single items (like a vector)
items.erase(std::remove_if(begin(items), end(items), [] (item*i) {
bool isActive = (*i)->update();
if (!isActive)
return true;
other_code_involving(*i);
return false;
}));
do while loop, it's flexable and fast and easy to read and write.
auto textRegion = m_pdfTextRegions.begin();
while(textRegion != m_pdfTextRegions.end())
{
if ((*textRegion)->glyphs.empty())
{
m_pdfTextRegions.erase(textRegion);
textRegion = m_pdfTextRegions.begin();
}
else
textRegion++;
}
I'd like to share my method. This method also allows the insertion of the element to the back of the list during iteration
#include <iostream>
#include <list>
int main(int argc, char **argv) {
std::list<int> d;
for (int i = 0; i < 12; ++i) {
d.push_back(i);
}
auto it = d.begin();
int nelem = d.size(); // number of current elements
for (int ielem = 0; ielem < nelem; ++ielem) {
auto &i = *it;
if (i % 2 == 0) {
it = d.erase(it);
} else {
if (i % 3 == 0) {
d.push_back(3*i);
}
++it;
}
}
for (auto i : d) {
std::cout << i << ", ";
}
std::cout << std::endl;
// result should be: 1, 3, 5, 7, 9, 11, 9, 27,
return 0;
}
I think you have a bug there, I code this way:
for (std::list<CAudioChannel *>::iterator itAudioChannel = audioChannels.begin();
itAudioChannel != audioChannels.end(); )
{
CAudioChannel *audioChannel = *itAudioChannel;
std::list<CAudioChannel *>::iterator itCurrentAudioChannel = itAudioChannel;
itAudioChannel++;
if (audioChannel->destroyMe)
{
audioChannels.erase(itCurrentAudioChannel);
delete audioChannel;
continue;
}
audioChannel->Mix(outBuffer, numSamples);
}

What's the simplest way to avoid game freezing while calling heavy functions in unity?

I'm currently developing a meta tic tac toe AI to play against in Unity. I would like to instantiate particles whenever the player plays a move. However, the particles freeze when the AI's move evaluation function is called. What is the simplest way to make the particles continue to move while the computer is calculating the best move? I've read documentation about unity Job system, but Job structs can't contain reference types which, here is a problem.
public void Play (List<Move> moves) {
int[,] grid = gB.stateGrid;
Move bestMove = new Move();
if (firstTurn)
{
bestMove.col = 4;
bestMove.row = 4;
firstTurn = false;
}
else
{
foreach (Move m in moves)
{
int e = EvalMove(m, level, true, grid, gB.subgridsStates, Mathf.NegativeInfinity, Mathf.Infinity);
m.value = e;
}
int best = moves.Select(x => x.value).Max();
List<Move> bestMoves = moves.Where(x => x.value == best).ToList();
bestMove = bestMoves[Random.Range(0, bestMoves.Count - 1)];
}
gB.PlaceToken(bestMove);
}
The function calculates the bestMove among all possible moves and then asks the game board script to place the corresponding token on the grid.
You can use Coroutine to do a heavy task and avoid freezing.
Change your method return type to IEnumerator
IEnumerator Heavy()
{
// some real heavy task
for (int i = 1; i < 10000000; i++)
{
balh();
yield return new WaitForEndOfFrame();
}
}
And simply call it like this:
StartCoroutine(Heavy());
You just have to run it on a MonoBehaviour. that's it.

Is it normal to solve a TSP with GA(Genetic Algorithyms) implementation takes much time?

I am working on GA for a project. I am trying to solve Travelling Salesman Problem using GA. I used array[] to store data, I think Arrays are much faster than List. But for any reason it takes too much time. e.g. With MaxPopulation = 100000, StartPopulation=1000 the program lasts to complete about 1 min. I want to know if this is a problem. If it is, how can I fix this?
A code part from my implementation:
public void StartAsync()
{
Task.Run(() =>
{
CreatePopulation();
currentPopSize = startPopNumber;
while (currentPopSize < maxPopNumber)
{
Tour[] elits = ElitChromosoms();
for (int i = 0; i < maxCrossingOver; i++)
{
if (currentPopSize >= maxPopNumber)
break;
int x = rnd.Next(elits.Length - 1);
int y = rnd.Next(elits.Length - 1);
Tour parent1 = elits[x];
Tour parent2 = elits[y];
Tour child = CrossingOver(parent1, parent2);
int mut = rnd.Next(100);
if (mutPosibility >= mut)
{
child = Mutation(child);
}
population[currentPopSize] = child;
currentPopSize++;
}
progress = currentPopSize * 100 / population.Length;
this.Progress = progress;
GC.Collect();
}
if (GACompleted != null)
GACompleted(this, EventArgs.Empty);
});
}
In here "elits" are the chromosoms that have greater fit value than the average fit value of the population.
Scientific papers suggest smaller population. Maybe you should follow what is written by the other authors. Having big population does not give you any advantage.
TSP can be solved by GA, but maybe it is not the most efficient approach to attack this problem. Look at this visual representation of TSP-GA: http://www.obitko.com/tutorials/genetic-algorithms/tsp-example.php
Ok. I have just found a solution. Instead of using an array with size of maxPopulation, change new generations with the old and bad one who has bad fitness. Now, I am working with a less sized array, which has length of 10000. The length was 1,000.000 before and it was taking too much time. Now, in every iteration, select best 1000 chromosomes and create new chromosomes using these as parent and replace to old and bad ones. This works perfect.
Code sample:
public void StartAsync()
{
CreatePopulation(); //Creates chromosoms for starting
currentProducedPopSize = popNumber; //produced chromosom number, starts with the length of the starting population
while (currentProducedPopSize < maxPopNumber && !stopped)
{
Tour[] elits = ElitChromosoms();//Gets best 1000 chromosoms
Array.Reverse(population);//Orders by descending
this.Best = elits[0];
//Create new chromosom as many as the number of bad chromosoms
for (int i = 0; i < population.Length - elits.Length; i++)
{
if (currentProducedPopSize >= maxPopNumber || stopped)
break;
int x = rnd.Next(elits.Length - 1);
int y = rnd.Next(elits.Length - 1);
Tour parent1 = elits[x];
Tour parent2 = elits[y];
Tour child = CrossingOver(parent1, parent2);
int mut = rnd.Next(100);
if (mutPosibility <= mut)
{
child = Mutation(child);
}
population[i] = child;//Replace new chromosoms
currentProducedPopSize++;//Increase produced chromosom number
}
progress = currentProducedPopSize * 100 / maxPopNumber;
this.Progress = progress;
GC.Collect();
}
stopped = false;
this.Best = population[population.Length - 1];
if (GACompleted != null)
GACompleted(this, EventArgs.Empty);
}
Tour[] ElitChromosoms()
{
Array.Sort(population);
Tour[] elits = new Tour[popNumber / 10];
Array.Copy(population, elits, elits.Length);
return elits;
}

what's different between StrCmpW and wcscmp?

Actually i changed code to next.
struct myclass {
bool operator() (std::wstring p1, std::wstring p2) {
int result = 0;
//// If character is alphabet, sorting need converse.
wint_t a1 = p1.at(0);
wint_t b2 = p2.at(0);
int r1 = iswalpha(a1);
int r2 = iswalpha(b2);
**// return code of iswalpha.
// 257 is Upper Alphabet,
// 258 is Lower Alphabet**
if ((r1 == 257 && r1 == 258) ||
(r2 == 258 && r2 == 257)) {
result = p2.compare(p1);
}
else {
result = p1.compare(p2);
}
if (result != 0) {
if (result == -1) {
return true;
}
else {
return false;
}
}
return false;
}
} wStrCompare;
void main() {
std::vector<std::wstring> wlist;
wlist.emplace_back(L"가나");
wlist.emplace_back(L"123");
wlist.emplace_back(L"abc");
wlist.emplace_back(L"타파");
wlist.emplace_back(L"하하");
wlist.emplace_back(L"!##$");
wlist.emplace_back(L"一二三");
wlist.emplace_back(L"好好");
wlist.emplace_back(L"QWERID");
wlist.emplace_back(L"ⓐⓑ");
wlist.emplace_back(L"☆★");
wlist.emplace_back(L"とばす");
std::sort(wlist.begin(), wlist.end(), wStrCompare);
}
Test Result
L"!##$"
L"123"
L"abc"
L"QWERID"
L"ⓐⓑ"
L"☆★"
L"とばす"
L"一二三"
L"好好"
L"가나"
L"타파"
L"하하"
is this good?
Please give me a some opinion.
Thanks!!
I change my code, but i still want to know "is there difference between StrCmpW and wcscmp" Please talk to me. thanks!
Old question
I use qsort with std::wstring(for unicode string), and use StrCmpW.
Previously, I used StrCmpLogicalW() with CString, CStringArray.
(These are depend on windows)
But my code run in linux too, not only in windows.
(CString is ATL(afx), StrCmpLogicalW() is in Shlwapi.h)
So I use std::wstring and wcscmp, but result is different.
Is there a difference between StrCmpW() and wcscmp()?
The Following is my code.(exactly not mine lol)
int wCmpName(const void* p1, const void *p2)
{
std::wstring* wszName1 = ((std::wstring *)(p1));
std::wstring* wszName2 = ((std::wstring *)(p2));
int wret = StrCmpW(wszName1->c_str(), wszName2->c_str());
// int wret = wcscmp(wszName1->c_str(), wszName2->c_str());
// When i use wcscmp, different result comes out.
return wret;
}
void wSort(std::vector<std::wstring> &arr)
{
qsort(arr.data(), arr.size(), sizeof(std::wstring), wCmpName);
}
Thanks!
Test Code
void main() {
std::vector<std::wstring> wlist;
wlist.emplace_back(L"가나");
wlist.emplace_back(L"123");
wlist.emplace_back(L"abc");
wlist.emplace_back(L"타파");
wlist.emplace_back(L"하하");
wlist.emplace_back(L"!##$");
wlist.emplace_back(L"一二三");
wlist.emplace_back(L"好好");
wlist.emplace_back(L"QWERID");
wlist.emplace_back(L"ⓐⓑ");
wlist.emplace_back(L"☆★");
wlist.emplace_back(L"とばす");
wSort(wlist);
}
Test Result
wcscmp
L"!##$"
L"123"
L"QWERID"
L"abc"
L"ⓐⓑ"
L"☆★"
L"とばす"
L"一二三"
L"好好"
L"가나"
L"타파"
L"하하"
StrCmpW
L"!##$"
L"☆★"
L"123"
L"ⓐⓑ"
L"abc"
L"QWERID"
L"とばす"
L"가나"
L"一二三"
L"타파"
L"하하"
L"好好"
p.s : WHY limit reputation?! limited Images, limited URLs.
Only text takes so long time.

Resources