Search code examples
iphoneiosnspredicategame-centergamekit

How to sort GKTurnBasedMatch by most recently active?


I am creating a simple word game with a menu screen in which I am displaying all of the user's active matches. I would like to sort this array of matches in order from most recently to least recently active, but the only timestamp property associated with players taking turns is a property of GKTurnBasedParticipant...GKTurnBasedMatch has no useful sorting property.

GKTurnBasedMatch has an array of GKTurnBasedParticipant objects as a property, so I would certainly be able to come up with some sort of solution, but I can't think of anything that wouldn't be really messy and inefficient. Is there any way something simple like NSPredicate could be used in a case like this to drill down into each array of participants, look at the latest timestamp and sort all the matches in one go?


Solution

  • I don't have an NSPredicate-based solution, or probably anything as elegant as you had hoped, but I ran into the same issue and wrote my own solution and it wasn't actually that bad.

    My solution is for a game that can only have two participants, so modify accordingly, but here is the code I ended up using:

    [myGamesArray sortUsingComparator:^NSComparisonResult(CHGame *game1, 
                                                          CHGame *game2) {
    
        if (YES == [game1 localPlayersTurn] && NO == [game2 localPlayersTurn]) {
            return NSOrderedAscending;
        } else if (NO == [game1 localPlayersTurn] && YES == [game2 localPlayersTurn]) {
            return NSOrderedDescending;
        }
    
        NSDate *lm1 = [game1.match lastMove];
        NSDate *lm2 = [game2.match lastMove];
        if (lm1 != nil && lm2 != nil) {
            return [lm1 compare:lm2];
        }
    
        return NSOrderedSame;
    
    }];
    

    where CHGame is a custom class I built for my games (which have a GKTurnBasedMatch match property), and the instance method localPlayersTurn returns a BOOL indicating whether or not it is the local participant's turn or not.

    And then I wrote a lastMove method in a category on GKTurnBasedMatch:

    - (NSDate *)lastMove {
        GKTurnBasedParticipant *localParticipant, *otherParticipant;
        NSDate *lastMove;
    
        for (GKTurnBasedParticipant *participant in self.participants) {
            if (YES == [participant.playerID isEqualToString:[GKLocalPlayer localPlayer].playerID]) {
                localParticipant = participant;
            } else {
                otherParticipant = participant;
            }
        }
    
        if (localParticipant == self.currentParticipant) {
            lastMove = otherParticipant.lastTurnDate;
        } else {
            lastMove = localParticipant.lastTurnDate;
        }
    
        return lastMove;
    }
    

    Again, this only works for two total participants, but would be easy to modify for any number of them.

    Hope this helps even though it's not exactly what you asked for.