I already have my brain broken with ai for tic-tac-toe type board game.
Problem is slow ai performance on high levels (even low levels has not so quick).
AI uses recursive method to find best move from number of available moves.
Here is some code:
#impelementation AIClass
- (NSMutableArray *)findLegalMoves
{
// Here is code that finds available legal moves
// Loop over board array
}
- (float)scoreOpponentsTurn:(float)min max:(float)max depth:(int)depth
{
moveType t; // moveType is struct defined in .h file
// typedef struct { int x, y; } moveType
NSMutableArray *moves = [self findLegalMoves];
for ( NSValue *val in moves ) {
[val getValue:&it]
float score = [self scoreMove:it min:min max:max depth:depth];
if ( score > min ) {
min = score;
}
if ( score > max ) {
min = 1000000000;
}
}
return min;
}
- (float)scoreMove:(moveType)m min:(float)min max:(float)max depth:(int)depth
{
NSMutableArray *changes = [[NSMutableArray alloc] init];
NSMutableArray *undo = [[NSMutableArray alloc] init];
float score;
[self.board evaluateChangesOnCol:m.x Row:m.y];
if ( [self.board checkForWin:&changes undo:&undo] ) {
score = 1000000000 + [self calcH]; //calcH - evals heuristic like sum of params
} else if ( depth > 0 ) {
score = - [self scoreOpponentsTurn:-1000000000 max:-min depth:depth - 1];
} else {
score = [self calcH];
}
[self.board applyChanges:undo];
}
- (moveType)findBestMove
{
NSMutableArray *legalMoves = [self findLegalMoves];
NSMutableArray *bestMoves = [[NSMutableArray alloc] init];
int min = -1000000000;
int max = 1000000000;
moveType move;
for ( NSValue *moveIt in legalMoves ) {
[moveIt getValue:&move];
float score = [self scoreMove:move min:min max:max depth:depth];
// Here i have some conditions to decide current move is best or not
}
// and pick random move from best moves and assign it to move variable
return move;
}
#end
And if number of legal moves like 3 and more (over recursive search it grows) this algorithm
works very slow.
It's my first objective-c experience.
Here is my guesses about how to improve performance:
Remove recursion (but I don't see another solution)
Use multithreading (how?)
May be use some ai library?
Sorry for my english.
Throwing away recursion in an algorithm that is a natural fit for recursion is not a good idea. Rather, you need to memoize your recursive solution. This common trick speeds up recursive solutions with common subproblems by orders of magnitude.
Consider these two sequences of moves:
x:(1,1) o:(2,1) x:(1,0) o:(2,0)
and
x:(1,0) o:(2,0) x:(1,1) o:(2,1)
The sequences are different, but they arrive at the same final state:
| | x | o
------------
| | x | o
Here is the root cause of the slowness: when your program arrives at a repeated state for the second time, it evaluates the position exactly as if it's the first time that it has seen it. This is wasteful: identical positions with three-move look-aheads will be evaluated four times; with four-move look-aheads, they would be evaluated eight times, and so on. This causes slowness proportional to 2^N, where N is the depth of your look-ahead.
Fixing this requires an addition of a lookup table. Given a state of the game, this table would give you the score for you or for the opponent, if such score has been calculated before. Your recursive functions would build a position key, and try a lookup in the score table. If the answer is there, it would be returned immediately. Otherwise, your function would construct the answer, and store it at the position key. Next time the same position occurs through a different series of moves, the answer would be reused.
You might want to try Alpha-beta pruning. It's possible that your game has as high branching factor, in which case you will want to avoid searching areas that won't affect the outcome.
You can also limit your search to a certain depth. Pick a depth that retrieves competent moves, but doesn't take too long.
Related
We want to add an array of doubles to a circular buffer in Objective C many times a second.
We are currently using a NSMutableArray nested within another NSMutableArray (2D array). This works fine but is too slow for our needs.
We want to add to the circular buffer many times a second. When we do this and do performance monitoring we see the call to removeObjectAtIndex:0 become a bottleneck (shift n-1 objects or O(n-1)). This is because we have many thousands of entries in our circular buffer.
We have looked at possibly using STL and std::deque. We have also looked at CHDataStructures. As you know, STL is in in C++ and can be integrated but is not as straight forward as an Objective C solution. CHDataStructures is getting dated and is not ARC compliant.
Please suggest how we should implement a circular buffer (for our array of doubles) for high performance with a code sample if possible.
Having read your comment (and thought about it a bit more) I realised use of a regular NSArray would be better, as there are no memory management issues (NSArrays retain their objects naturally). Just define the capacity up front to avoid it having to reallocate memory as it runs. Calling [self resetBuffer] will quickly release all data and start again.
#define BUFFER_SIZE 1000
#implementation ViewController {
NSMutableArray *circularBuffer;
NSUInteger bufferHead;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
if (self = [super initWithCoder:aDecoder]) {
[self resetBuffer];
}
return self;
}
- (void)addArrayToBuffer:(NSMutableArray *)incoming {
if (bufferHead < circularBuffer.count)
[circularBuffer replaceObjectAtIndex:bufferHead withObject:incoming];
else
[circularBuffer addObject:incoming];
bufferHead = (bufferHead + 1) % BUFFER_SIZE;
}
- (NSArray *)bufferContent {
if (circularBuffer.count < BUFFER_SIZE) {
return circularBuffer;
} else {
NSArray *arrHead = [circularBuffer objectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, bufferHead)]];
NSArray *arrTail = [circularBuffer objectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(bufferHead, BUFFER_SIZE-bufferHead)]];
return [arrTail arrayByAddingObjectsFromArray:arrHead];
}
}
- (void)resetBuffer {
circularBuffer = [NSMutableArray arrayWithCapacity:BUFFER_SIZE];
bufferHead = 0;
}
So my friend asked me this question as interview practice:
Using Objective-C & Foundation Kit, Write a method that takes a single digit int, and logs out to the console the precise result of that int being raised to the power of 100.
Initially I thought it sounded easy, but then I realized that even a single digit number raised to the power of 100 would quickly come close to 100 digits, which would overflow.
So I tried tackling this problem by creating an NSArray w/ NSNumbers (for reflection), where each object in the array is a place in the final result number. Then I perform the multiplication math (including factoring in carries), and then print out a string formed by concatenating the objects in the array. Here is my implementation w/ input 3:
NSNumber *firstNum = [NSNumber numberWithInteger:3];
NSMutableArray *numArray = [NSMutableArray arrayWithArray:#[firstNum]];
for( int i=0; i<99; i++)
{
int previousCarry = 0;
for( int j=0; j<[numArray count]; j++)
{
int newInt = [firstNum intValue] * [[numArray objectAtIndex:j] intValue] + previousCarry;
NSNumber *calculation = [NSNumber numberWithInteger:newInt];
previousCarry = [calculation intValue]/10;
NSNumber *newValue = [NSNumber numberWithInteger:(newInt % 10)];
[numArray replaceObjectAtIndex:j withObject:newValue];
}
if(previousCarry > 0)
{
[numArray addObject:[NSNumber numberWithInteger:previousCarry]];
}
}
NSArray* reversedArray = [[numArray reverseObjectEnumerator] allObjects];
NSString *finalNumber = [reversedArray componentsJoinedByString:#""];
NSLog(#"%#", finalNumber);
This isn't a problem out of a textbook or anything so I don't have any reference to double check my work. How does this solution sound to you guys? I'm a little worried that it's pretty naive even though the complexity is O(N), I can't help but feel like I'm not utilizing a type/class or method unique to Objective-C or Foundation Kit that would maybe produce a more optimal solution-- or at the very least make the algorithm cleaner and look more impressive
Write a method that takes a single digit int, and logs out to the console the precise result of that int being raised to the power of 100.
That strikes me as a typical interview "trick"[*] question - "single digit", "logs out to console"...
Here goes:
NSString *singleDigitTo100(int d)
{
static NSString *powers[] =
{
#"0",
#"1",
#"1267650600228229401496703205376",
#"515377520732011331036461129765621272702107522001",
#"1606938044258990275541962092341162602522202993782792835301376",
#"7888609052210118054117285652827862296732064351090230047702789306640625",
#"653318623500070906096690267158057820537143710472954871543071966369497141477376",
#"3234476509624757991344647769100216810857203198904625400933895331391691459636928060001",
#"2037035976334486086268445688409378161051468393665936250636140449354381299763336706183397376",
#"265613988875874769338781322035779626829233452653394495974574961739092490901302182994384699044001"
};
return powers[d % 10]; // simple bounds check...
}
And the rest is easy :-)
And if you are wondering, those numbers came from bc - standard command line calculator in U*ix and hence OS X. You could of course invoke bc from Objective-C if you really want to calculate the answers on the fly.
[*] It is not really a "trick" question but asking if you understand that sometimes the best solution is a simple lookup table.
As you have correctly figured out, you will need to use some sort of big integer library. This is a nice example you can refer to: https://mattmccutchen.net/bigint/
Furthermore, you can calculate x^n in O(lg(n)) rather than in O(n), using divide and conquer:
f(x, n):
if n == 0: # Stopping condition
return 1
temp = f(n/2)
result = temp * temp
if n%2 == 1:
result *= x
return result
x = 5 # Or another one digit number.
n = 100
result = f(x, 100) # This is the result you are looking for.
Note that x represents your integer and n the power you are raising x to.
Here is my Objective-C implementation of a disjoint set.
- Positive number point to parent.
- Negative number indicate root & children count. (So they each start disjointed at -1.)
- The index acts as the data I am grouping.
Seems to work ok... just had a couple questions.
find: How can I compress the path? Because I am not doing it recursively, do I have to store the path and loop it again to set after find root?
join: I am basing join on children count instead of depth!? I guess that is not right. Do I need to do something special during join if depths equal?
Thanks.
DisjointSet.h
#interface DisjointSet : NSObject
{
NSMutableArray *_array;
}
- (id)initWithSize:(NSInteger)size;
- (NSInteger)find:(NSInteger)item;
- (void)join:(NSInteger)root1 root2:(NSInteger)root2;
#end
DisjointSet.m
#import "DisjointSet.h"
#implementation DisjointSet
- (id)initWithSize:(NSInteger)size
{
self = [super init];
if (self)
{
_array = [NSMutableArray arrayWithCapacity:size];
for (NSInteger i = 0; i < size; i++)
{
[_array addObject:[NSNumber numberWithInteger:-1]];
}
}
return self;
}
- (NSInteger)find:(NSInteger)item
{
while ([[_array objectAtIndex:item] integerValue] >= 0)
{
item = [[_array objectAtIndex:item] integerValue];
}
return item;
}
- (void)join:(NSInteger)root1 root2:(NSInteger)root2
{
if (root1 == root2) return;
NSInteger data1 = [[_array objectAtIndex:root1] integerValue];
NSInteger data2 = [[_array objectAtIndex:root2] integerValue];
if (data2 < data1)
{
[_array setObject:[NSNumber numberWithInteger:data2 + data1] atIndexedSubscript:root2];
[_array setObject:[NSNumber numberWithInteger:root2] atIndexedSubscript:root1];
}
else
{
[_array setObject:[NSNumber numberWithInteger:data1 + data2] atIndexedSubscript:root1];
[_array setObject:[NSNumber numberWithInteger:root1] atIndexedSubscript:root2];
}
}
#end
For the find operation, there is no need to store the path (separately from your _array) or to use recursion. Either of those approaches requires O(P) storage (P = path length). Instead, you can just traverse the path twice. The first time, you find the root. The second time, you set all of the children to point to the root. This takes O(P) time and O(1) storage.
- (NSInteger)findItem:(NSInteger)item {
NSInteger root;
NSNumber *rootObject = nil;
for (NSInteger i = item; !rootObject; ) {
NSInteger parent = [_array[i] integerValue];
if (parent < 0) {
root = i;
rootObject = #(i);
}
i = parent;
}
for (NSInteger i = item; i != root; ) {
NSInteger parent = [_array[i] integerValue];
_array[i] = rootObject;
i = parent;
}
return root;
}
For the merge operation, you want to store each root's rank (which is an upper bound on its depth), not each root's descendant count. Storing each root's rank allows you to merge the shorter tree into the taller tree, which guarantees O(log N) time for find operations. The rank only increases when the trees to be merged have equal rank.
- (void)joinItem:(NSInteger)a item:(NSInteger)b {
NSInteger aRank = -[_array[a] integerValue];
NSInteger bRank = -[_array[b] integerValue];
if (aRank < bRank) {
NSInteger t = a;
a = b;
b = t;
} else if (aRank == bRank) {
_array[a] = #(-aRank - 1);
}
_array[b] = #(a);
}
You definitely should implement path compression using recursion. I would not even think about trying to do it non-recursively.
Implementing the disjoin-set datastructure should be very easy, and can be done in few lines. Its very, very easy to translate it from the pseudocode to any programming language. You can find the pseudocode on Wikipedia. (Unfortunately, I can't read Objective-C, so I cannot really judge wether your code is correct or not).
Yes. To implement highest ancestor compression without recursion you need to maintain your own list. Make one pass up the chain to get pointers to the sets that need their parent pointers changed and also to learn the root. Then make a second pass to update the necessary parent pointers.
The recursive method is doing the same thing. The first pass is the "winding up" of the recursion, which stores the sets needing parent pointer updates on the program stack. The second pass is in reverse as the recursion unwinds.
I differ with those who say the recursive method is always best. In a reasonable number systems (especially embedded ones), the program stack is of limited size. There are cases where many unions are performed in a row before a find. In such cases, the parent chain can be O(n) in size for n elements. Here collapsing by recursion can blow out the stack. Since you are working in Objective C, this may be iOS. I do not know the default stack size there, but if you use recursion it's worth looking at. It might be smaller than you think. This article implies 512K for secondary threads and 1Mb for the main thread.
Iterative, constant space alternative
Actually the main reason I'm writing is to point out that you still get O(log^* n) for n ammortized operations -- just a shade less efficient than collapsing, and still effectively O(1) -- if you only do factor-of-two compression: in the find operation, change parent pointers so that they point to the grandparents instead instead of the root. This can be done with iteration in constant storage. This lecture at Princeton talks about this algorithm and implements it in a loop with 5 lines of C. See slide 29.
I have a Core Data model defined with two attributes
(Double) latitude
(Double) longitude
Now, I would like to fetched these objects and sort them depending on how far they are compared to the user's current location. I already know how to get the current location, but what I still can't figure out is how to sort the results depending on two attributes.
I've searched for something similar but I'm still a bit confused.
That'd be great if someone could point me to the right direction.
Thanks
Sorting with a comparator block is quite easy
NSArray *positions = //all fetched positions
CLLocation *currentLocation = // You said that you know how to get this.
positions = [positions sortedArrayUsingComparator: ^(id a, id b) {
CLLocation *locationA = [CLLocation initWithLatitude:a.latitude longitude:a.longitude];
CLLocation *locationB = [CLLocation initWithLatitude:b.latitude longitude:b.longitude];
CLLocationDistance dist_a= [locationA distanceFromLocation: currentLocation];
CLLocationDistance dist_b= [locationB distanceFromLocation: currentLocation];
if ( dist_a < dist_b ) {
return (NSComparisonResult)NSOrderedAscending;
} else if ( dist_a > dist_b) {
return (NSComparisonResult)NSOrderedDescending;
} else {
return (NSComparisonResult)NSOrderedSame;
}
}
As I just learned from lnafziger, you should add that useful hack/workaround¹, he is showing, to this.
¹choose form this words the one, that has the most positive connotation for you
You probably want to convert you long/lat pairs into a geographical distance between points and then sort on that single attribute.
Here's an article on some conversion methods, depending on what approximations you want to accept: http://en.wikipedia.org/wiki/Geographical_distance
Well, you can't.
Not just by sorting lat/long by itself anyway. :)
You will need to have a property that contains the distance from your current location. You can do this by adding a transient property which is calculated as needed or creating another array with the distances (probably easier).
To calculate your distance from your current location, use this method:
CLLocation *currentLocation = // You said that you know how to get this.
CLLocation *storedLocation = [CLLocation initWithLatitude:object.latitude
longitude:object.longitude];
/*
* Calculate distance in meters
* Note that there is a bug in distanceFromLocation and it gives different
* values depending on whether you are going TO or FROM a location.
* The correct distance is the average of the two:
*/
CLLocationDistance *distance1 = [currentLocation distanceFromLocation:storedLocation];
CLLocationDistance *distance2 = [storedLocation distanceFromLocation:currentLocation];
CLLocationDistance *distance = distance1 / 2 + distance2 / 2;
I've written a small utility program that identifies duplicate tracks in iTunes.
The actual matching of tracks takes a long time, and I'd like to optimize it.
I am storing track data in an NSMutableDictionary that stores individual track data in
NSMutableDictionaries keyed by trackID. These individual track dictionaries have
at least the following keys:
TrackID
Name
Artist
Duration (in milli ####.####)
To determine if any tracks match one another, I must check:
If the duration of two tracks are within 5 seconds of each other
Name matches
Artist matches
The slow way for me to do it is using two for-loops:
-(void)findDuplicateTracks {
NSArray *allTracks = [tracks allValues];
BOOL isMatch = NO;
int numMatches = 0;
// outer loop
NSMutableDictionary *track = nil;
NSMutableDictionary *otherTrack = nil;
for (int i = 0; i < [allTracks count]; i++) {
track = [allTracks objectAtIndex:i];
NSDictionary *summary = nil;
if (![claimedTracks containsObject:track]) {
NSAutoreleasePool *aPool = [[NSAutoreleasePool alloc] init];
NSUInteger duration1 = (NSUInteger) [track objectForKey:kTotalTime];
NSString *nName = [track objectForKey:knName];
NSString *nArtist = [track objectForKey:knArtist];
// inner loop - no need to check tracks that have
// already appeared in i
for (int j = i + 1; j < [allTracks count]; j++) {
otherTrack = [allTracks objectAtIndex:j];
if (![claimedTracks containsObject:otherTrack]) {
NSUInteger duration2 = (NSUInteger)[otherTrack objectForKey:kTotalTime];
// duration check
isMatch = (abs(duration1 - duration2) < kDurationThreshold);
// match name
if (isMatch) {
NSString *onName = [otherTrack objectForKey:knName];
isMatch = [nName isEqualToString:onName];
}
// match artist
if (isMatch) {
NSString *onArtist = [otherTrack objectForKey:knArtist];
isMatch = [nArtist isEqualToString:onArtist];
}
// save match data
if (isMatch) {
++numMatches;
// claim both tracks
[claimedTracks addObject:track];
[claimedTracks addObject:otherTrack];
if (![summary isMemberOfClass:[NSDictionary class]]) {
[track setObject:[NSNumber numberWithBool:NO] forKey:#"willDelete"];
summary = [self dictionarySummaryForTrack:track];
}
[otherTrack setObject:[NSNumber numberWithBool:NO] forKey:#"willDelete"];
[[summary objectForKey:kMatches]
addObject:otherTrack];
}
}
}
[aPool drain];
}
}
}
This becomes quite slow for large music libraries, and only uses 1
processor. One recommended optimization was to use blocks and process
the tracks in batches (of 100 tracks). I tried that. If my code
originally took 9 hours to run, it now takes about 2 hours on a
quad-core. That's still too slow. But (talking above my pay grade here)
perhaps there is a way to store all the values I need in a C structure that "fits on the stack" and then I wouldn't have to fetch the values from slower memory. This seems too low-level for me, but I'm willing to learn if I had an example.
BTW, I profiled this in Instruments and [NSCFSet member:] takes up
86.6% percent of the CPU time.
Then I thought I should extract all the durations into a sorted array so I would not have
to look up the duration value in the dictionary. I think that is a good
idea, but when I started to implement it, I wondered how to determine
the best batch size.
If I have the following durations:
2 2 3 4 5 6 6 16 17 38 59 Duration
0 1 2 3 4 5 6 7 8 9 10 Index
Then just by iterating over the array, I know that to find matching
tracks of the song at index 0, I only need to compare it against songs
up to index 6. That's great, I have my first batch. But now I have to
start over at index 1 only to find that it's batch should also stop at
index 6 and exclude index 0. I'm assuming I'm wasting a lot of
processing cycles here determining what the batch should be/the duration
matches. This seemed like a "set" problem, but we didn't do much of
that in my Intro to Algorithms class.
My questions are:
1) What is the most efficient way to identify matching tracks? Is it
something similar to what's above? Is it using disjoint and [unified]
set operations that are slightly above my knowledge level? Is it
filtering arrays using NSArray? Is there an online resource that
describes this problem and solution?
I am willing to restructure the tracks dictionary in whatever way
(datastructure) is most efficient. I had at first thought I needed to
perform many lookups by TrackID, but that is no longer the case.
2) Is there a more efficient way to approach this problem? How do you
rock stars go from paragraph 1 to an optimized solution?
I have searched for the answer, longer than I care to admit, and found
these interesting, but unhelpful answers:
find duplicates
Find all duplicates and missing values in a sorted array
Thanks for any help you can provide,
Lance
My first thought is to maintain some sorted collections as indices into your dictionary so you can stop doing an O(n^2) search comparing every track to every other track.
If you had arrays of TrackIDs sorted by duration then for any track you could do a more efficient O(log n) binary search to find tracks with durations within your 5 second tolerance.
Even better for artist and name you can store a dictionary keyed on the artist or track name whose values are arrays of TrackIDs. Then you only need a O(1) lookup to get the set of tracks for a particular artist which should allow you to very quickly determine if there are any possible duplicates.
Finally if you've built that sort of dictionary of titles to TrackIDs then you can go through all of it's keys and only search for duplicates when there are multiple tracks with the same title. Doing further comparisons only when there are multiple tracks with the same title should eliminate a significant percentage of the library and massively reduce your search time (down to O(n) to build the dictionary and another O(n) for a worst case search for duplicates still leaves you at O(n) rather than the O(n^2) you have now).
If nothing else do that last optimization, the resulting performance increase should be huge for an library without a significant number of duplicates:
NSMutableArray *possibleDuplicates = [NSMutableArray array];
NSMutableDictionary *knownTitles = [NSMutableDictionary dictionary];
for (NSMutableDictionary *track in [tracks allKeys]) {
if ([knownTitles objectForKey:[track objectForKey:#"title"]] != nil) {
[possibleDuplicates addObject:track];
}
else {
[knownTitles addObject:[track objectForKey:#"TrackID"] forKey:[track objectForKey:#"title"]];
}
}
//check for duplicates of the tracks in possibleDuplicates only.
There are several ways to do this, but here's my first naïve guess:
Have a mutable dictionary.
The keys in this dictionary are the names of the songs.
The value of each key is another mutable dictionary.
The keys of this secondary mutable dictionary are the artists.
The value of each key is a mutable array of songs.
You'd end up with something like this:
NSArray *songs = ...; //your array of songs
NSMutableDictionary *nameCache = [NSMutableDictionary dictionary];
for (Song *song in songs) {
NSString *name = [song name];
NSMutableDictionary *artistCache = [nameCache objectForKey:name];
if (artistCache == nil) {
artistCache = [NSMutableDictionary dictionary];
[nameCache setObject:artistCache forKey:name];
}
NSString *artist = [song artist];
NSMutableArray *songCache = [artistCache objectForKey:artist];
if (songCache == nil) {
songCache = [NSMutableArray array];
[artistCache setObject:songCache forKey:artist];
}
for (Song *otherSong in songCache) {
//these are songs that have the same name and artist
NSTimeInterval myDuration = [song duration];
NSTimeInterval otherDuration = [otherSong duration];
if (fabs(myDuration - otherDuration) < 5.0f) {
//name matches, artist matches, and their difference in duration is less than 5 seconds
}
}
[songCache addObject:song];
}
This is a worst-case O(n2) algorithm (if every song has the same name, artist, and duration). It's a best-case O(n) algorithm (if every song has a different name/artist/duration), and will realistically end up being closer to O(n) than to O(n2) (most likely).