/// <summary> /// This routine handles sync request aspects that require fetching a list of all the puzzles the team /// has solved. /// </summary> private async Task HandleSyncAspectsRequiringListOfSolvedPuzzles(DecodedSyncRequest request, SyncResponse response, string puzzleGroup, int teamId, int eventId, int puzzleId) { // If the requester isn't asking for pieces (by setting MinSolveCount to null), and isn't asking about // whether any puzzle IDs are solved, we can save time by not querying the list of solved puzzles. if (request.MinSolveCount == null && (request.QueryPuzzleIds == null || request.QueryPuzzleIds.Count == 0)) { return; } // If the request is asking which of the puzzle IDs in request.QueryPuzzleIds has been // solved, create a HashSet so that we can quickly look up if an ID is in that list. HashSet <int> queryPuzzleIdSet = null; if (request.QueryPuzzleIds != null) { queryPuzzleIdSet = new HashSet <int>(); foreach (var queryPuzzleId in request.QueryPuzzleIds) { queryPuzzleIdSet.Add(queryPuzzleId); } } // Get a list of all the puzzles this team has solved from this event. List <Puzzle> solves = await(from state in context.PuzzleStatePerTeam where state.TeamID == teamId && state.SolvedTime != null select state.Puzzle).ToListAsync(); int maxSolveCount = 0; List <int> solvedPuzzles = new List <int>(); foreach (var solvedPuzzle in solves) { // If the request is asking whether certain puzzles are solved, check if it's // in the set and, if so, put it in the list of solved puzzles to inform the // requester of. Also, if we've been asked to query all puzzles in the puzzle's // group and this is one of them, put it in the list of solved puzzles. if (queryPuzzleIdSet != null && queryPuzzleIdSet.Contains(solvedPuzzle.ID)) { solvedPuzzles.Add(solvedPuzzle.ID); } else if (request.QueryAllInGroup && solvedPuzzle.Group == puzzleGroup) { solvedPuzzles.Add(solvedPuzzle.ID); } // When counting solves, only count puzzles if they're not in the same group // as the puzzle being synced, and only if they're worth at least 10 points // and exactly 0 hint coins. if (puzzleGroup == null || solvedPuzzle.Group != puzzleGroup) { if (solvedPuzzle.SolveValue >= 10 && solvedPuzzle.HintCoinsForSolve == 0) { maxSolveCount += 1; } } // If the user solved a cheat code in this group, treat it as a solve count of 1000. // The reason we require the cheat code to be in the same group as the puzzle being // sync'ed is to defend against mistakes by authors in other groups. If an author // of a puzzle in another group accidentally sets the cheat-code flag on their // puzzle, we don't want to consequently give all teams that solve it all pieces of // the puzzle being sync'ed. if (solvedPuzzle.IsCheatCode && solvedPuzzle.Group == puzzleGroup) { maxSolveCount += 1000; } } // If the requester is asking for puzzle pieces (by setting request.MinSolveCount != null) // and if there are pieces of the puzzle that the requester has now earned but hasn't // yet received, because the maximum solve count they've earned is at least as high // as the minimum solve count the requester is asking for, then return those pieces. // Note that request.MinSolveCount is the minimum solve count of tokens the requester // *hasn't* seen yet. if (request.MinSolveCount != null && maxSolveCount >= request.MinSolveCount) { List <Piece> pieces = await(from piece in context.Pieces where piece.ProgressLevel >= request.MinSolveCount && piece.ProgressLevel <= maxSolveCount && piece.PuzzleID == puzzleId select piece).ToListAsync(); response.SetMinAndMaxSolveCountAndPieces(request.MinSolveCount.Value, maxSolveCount, pieces); } // If we found some solved puzzles in request.QueryPuzzleIds, return those in the // response. if (solvedPuzzles.Count > 0) { response.SetSolvedPuzzles(solvedPuzzles); } }
/// <summary> /// This routine handles sync request aspects that require fetching a list of all the puzzles the team /// has solved. /// </summary> private async Task HandleSyncAspectsRequiringListOfSolvedPuzzles(DecodedSyncRequest request, SyncResponse response, string groupExcludedFromSolveCount, int teamId, int eventId) { // If the requester isn't asking for pieces (by setting MinSolveCount to null), and isn't asking about // whether any puzzle IDs are solved, we can save time by not querying the list of solved puzzles. if (request.MinSolveCount == null && (request.QueryPuzzleIds == null || request.QueryPuzzleIds.Count == 0)) { return; } // If the request is asking which of the puzzle IDs in request.QueryPuzzleIds has been // solved, create a HashSet so that we can quickly look up if an ID is in that list. HashSet <int> queryPuzzleIdSet = null; if (request.QueryPuzzleIds != null) { queryPuzzleIdSet = new HashSet <int>(); foreach (var queryPuzzleId in request.QueryPuzzleIds) { queryPuzzleIdSet.Add(queryPuzzleId); } } // Get a list of all the puzzles this team has solved from this event. List <Puzzle> solves = await(from state in context.PuzzleStatePerTeam where state.TeamID == teamId && state.SolvedTime != null && state.Puzzle.Event.ID == eventId select state.Puzzle).ToListAsync(); int maxSolveCount = 0; List <int> solvedPuzzles = new List <int>(); foreach (var solvedPuzzle in solves) { // If the request is asking whether certain puzzles are solved, check if it's // in the set and, if so, put it in the list of solved puzzles to inform the // requester of. if (queryPuzzleIdSet != null && queryPuzzleIdSet.Contains(solvedPuzzle.ID)) { solvedPuzzles.Add(solvedPuzzle.ID); } // When counting solves, only count puzzles if they're not in the group that doesn't // count toward the solve count, and only if they're worth at least 10 points. if (groupExcludedFromSolveCount == null || solvedPuzzle.Group != groupExcludedFromSolveCount) { if (solvedPuzzle.SolveValue >= 10) { maxSolveCount += 1; } } // If the user solved a cheat code, treat it as a solve count of 1000. if (solvedPuzzle.IsCheatCode) { maxSolveCount += 1000; } } // If the requester is asking for puzzle pieces (by setting request.MinSolveCount != null) // and if there are pieces of the puzzle that the requester has now earned but hasn't // yet received, because the maximum solve count they've earned is at least as high // as the minimum solve count the requester is asking for, then return those pieces. // Note that request.MinSolveCount is the minimum solve count of tokens the requester // *hasn't* seen yet. if (request.MinSolveCount != null && maxSolveCount >= request.MinSolveCount) { List <Piece> pieces = await(from piece in context.Pieces where piece.ProgressLevel >= request.MinSolveCount && piece.ProgressLevel <= maxSolveCount select piece).ToListAsync(); response.SetMinAndMaxSolveCountAndPieces(request.MinSolveCount.Value, maxSolveCount, pieces); } // If we found some solved puzzles in request.QueryPuzzleIds, return those in the // response. if (solvedPuzzles.Count > 0) { response.SetSolvedPuzzles(solvedPuzzles); } }