Intern: Jocelyn Tseng
Intern Manager: Carmen Salvador
- Overview
- Product Spec
- Wireframes
- Schema
- Walkthroughs
- Playmate's Recommendation System
- External Resources
Playmate is a platform where sports players can conveniently find others to play with given a time and place.
- Category: Sports social networking
- Mobile: Playmate will be developed for iOS.
- Story: Sports players are able to connect with others on the app and then meet up in real life to socialize and play the sport they love.
- Market: People who play any type of sport or would like to get into sports can benefit from Playmate.
- Habit: Playmate will be used when users wish to schedule a session to play a certain sport. Depending on how often a user wants to play, this app may be used on any type of basis, from daily to monthly.
- Scope: Playmate's focus is on creating sports sessions and filtering sessions to find suitable ones to join. Playmate also supports personalized user profiles, friending between users, and session invitations to and from friends.
Required Must-have Stories
- User can create account and log in
- User can customize their profile
- User can view their own sessions in a carousel view on home tab
- User can see own sessions on a calendar
- User can explore nearby sessions on a map
- User can search for sessions based on filters they set
- User can join an existing session after search
- User can remove themself from a session
- User can create session if no existing ones match their liking
- User can search for location on map to set their session location
- User can send and approve or deny friend requests
- User can remove friend
Optional Nice-to-have Stories
- User can edit their profile
- User will be notified of upcoming sessions through iOS notifications
- User can open session location in Apple or Google maps
- User can invite friends to a session they are already in
- User can view and accept or deny invite
- User can delete a session they created
- User can view their Playmate and session statistics
- User can take preferences quiz to get better suggestions
- User will be suggested sessions based on an AI heuristic
- Description of Playamte's recommendation system is in MORE_README.md
- Home Tab
- View upcoming sessions in a carousel view
- View suggested sessions in the same way
- Take preferences quiz to get better suggestions
- Calendar
- See own sessions on a calendar
- Explore Nearby
- Explore nearby sessions on a map
- Session Details
- Open session location in Apple or Google maps
- Join a session
- Leave a session
- Delete a session they created
- Invite friends to a session they are already in
- Search Tab
- Search for existing sessions
- Apply filters to search for desired session properties
- Can search for location on map to set their session location
- Create Tab
- Create session if no existing ones match their liking
- Profile Tab
- Customize their profile
- Notifications
- Approve or deny friend requests
- View and accept or deny invite
- Player Profile
- Send friend requests and remove friend
- View their Playmate and session statistics
Tab Navigation (Tab to Screen)
- Home Page
- Search
- Calendar
- Profile
Flow Navigation (Screen to Screen)
- Welcome Screen
- If do not have account: Create Account
- If have account: Login Screen
- Home
- Notifications View
- Take Quiz Views (Composed of five view controllers)
- Explore Nearby
- Map Filters View
- Select Location View
- Map Filters View
- My schedule
- Session Details
- Upcoming Sessions
- Session Details
- Suggested Sessions
- Session Details
- Search
- Session Details
- Filter Settings
- Select Location View
- Create
- Select Location View
- How to Select Location View
- Select Location View
- Profile
- Friends List
- Player Profile View (Continues -> Friend List -> Player Profile -> ...)
- Notifications View
- Incoming Friend Requests
- Outgoing Friend Requests
- Invitations
- Edit Profile
- Friends List
Property | Type | Description |
---|---|---|
sport | String | Which sport players in this session will play |
skillLevel | String | Skill level assigned to the session |
creator | Pointer to PFUser | Profile of user who created the session |
playersList | Array(of pointers to PFUser ) | List of users who are participating in the session |
occursAt | DateTime | Date and time of when the session occurs |
duration | Number | Length of the session in hours and minutes |
location | Pointer to PFObject(Location) | Location where session occurs |
capacity | Number | Total number of people who can be part of the session |
occupied | Number | Current number of people who are part of the session |
Property | Type | Description |
---|---|---|
longitude | Number | Longitude of the location on a map |
latitude | Number | Latitude of the location on a map |
locationName | String | Name of the location |
Property | Type | Description |
---|---|---|
userObjectId | String | objectId of the user this belongs to |
friendsList | Array | List of user objectId's of this person's friends |
pendingList | Array | List of user objectId's of people whom this user has sent friend request to and other user has not replied |
Property | Type | Description |
---|---|---|
userObjectId | String | objectId of the user this belongs to |
playSportsList | Array | List of the sports this user said they play |
dontPlaySportsList | Array | List of sports this user said they do not want to play |
gendersList | Array | List of preferred Playmate gender of this user |
ageGroupsList | Array | List of preferred Playmate age groups of this user |
Property | Type | Description |
---|---|---|
invitationToId | String | objectId of the user this invitation is to |
invitationFromId | String | objectId of the user this invitation is from |
sessionObjectId | String | objectId of the session this invitation is for |
Property | Type | Description |
---|---|---|
username(+) | String | User's username |
password(+) | String | User's password |
email(+) | String | User's email |
profileImage | Pointer to PFFileObject | Profile image uploaded by user |
firstName | String | User's first name |
lastName | String | User's last name |
birthday | DateTime | User's birthday |
gender | String | User's gender |
numFriends | Number | Number of friends user has |
friendsList | Array(of PFUser) | List of friends |
biography(-) | String | User's biography |
sessionsDictionary(-) | Dictionary | User's session history where key is sport and value is array of session objectId's for that sport |
playerConnection(-) | String | objectId of user's player connection object that stores friend data |
quizResult | String | objectId of user's quiz result object that holds quiz data after they take it |
+:(default PFUser property)
-:(optional, nil by default)
-
Network requests by screen
- Welcome Screen
- If do not have account: Create Account
- (Create/POST) Create a user profile
- If have account: Login Screen
- (Read/GET) Query logged in user account
- If do not have account: Create Account
- Home
- Notifications View
- (Read/GET) Query Incoming FriendRequests objects, Outgoing Requests, and Invitations objects
- Take Quiz Views (Composed of five view controllers)
- (Create/POST) Create QuizResult object if is user's first time taking quiz
- (Update/PUT) Update QuizResult if user has existing result
- Explore Nearby
- (Read/GET) Query SportsSessions to display on map and according to filters
- My schedule
- Each Day
- (Read/GET) Query SportsSessions that logged in user is part of on a certain day
- Each Day
- Upcoming Sessions
- (Read/GET) Query this user's upcoming SportsSessions
- Suggested Sessions
- (Read/GET) Query this user's RecommendationData object and get suggested sesions list
- Notifications View
- Session Details
- (Read/GET) Query SportsSession class object to display
- Search
- (Read/GET) Query all SportsSessions in the entire database
- Filter Settings
- Query SportsSessions according to filters
- Create
- (Create/POST) Create new SportsSession object
- Profile
- Friends List
- (Read/GET) Query friends list from this user's profile
- Player Profile View
- (Read/GET) Query PFUser corresponding to this profile
- Notifications View
- (Read/GET) Query Incoming FriendRequests objects, Outgoing Requests, and Invitations objects
- Edit Profile
- (Update/PUT) Add to user's profile object if changes are made
- Friends List
- Welcome Screen
-
GeoAPIfy Network Requests (Endpoint: https://api.geoapify.com/v1/)
- Geocoding
NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:10.0]; NSURLSessionDataTask *task = [self.session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { if (error != nil) { [Helpers handleAlert:error withTitle:[Strings errorString] withMessage:nil forViewController:self]; completion(nil, error); } else { NSDictionary *dataDictionary = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil]; // parse dictionary NSArray *results = dataDictionary[@"results"]; if (results.count == 0) { completion(nil, nil); } else { NSDictionary *firstResult = results[0]; Location *loc = [Location new]; loc.lat = [NSNumber numberWithDouble:[firstResult[@"lat"] doubleValue]]; loc.lng = [NSNumber numberWithDouble:[firstResult[@"lon"] doubleValue]]; loc.locationName = firstResult[@"formatted"]; completion(loc, nil); } } }];
- Reverse Geocoding
NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:10.0]; NSURLSessionDataTask *task = [self.session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { if (error != nil) { // handle alert if need be [Helpers handleAlert:error withTitle:[Strings errorString] withMessage:nil forViewController:self]; completion(nil, error); } else { // retrieve data NSDictionary *dataDictionary = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil]; // parse dictionary NSDictionary *result = dataDictionary[@"features"][0][@"properties"]; completion(result[@"formatted"], nil); } }];
- Geocoding
(Recommended Playback Speed: 1.5x)
create.login.MP4
- Home Tab, Explore Nearby, and My Schedule
home.explore.schedule.MP4
- Suggested Sessions and Preferences Quiz
suggestions.quiz.MP4
- Create, Search, and Invite
create.invite.search.MP4
- Profile and Friend Requests
profile.friendreqs.MP4
- Notification Feature (Session notifications are ten minutes in advance)
localnotifs.MP4
The goal of Playmate's Recommendation System is to suggest sessions to users based on their preferences and session histories. Each user will be suggested sessions that are catered towards their unique taste and according to our algorithm, are the sessions they would most likely want to join if they were to search themselves.
Like any AI algorithm, Playmate's Recommendation System requires user data such as preferred sports, gender, age groups, location, etc. to suggest the most optimal sessions. This data will be acquired through what the user has already supplied to us by joining sessions and voluntarily taking the preferences quiz.
Playmate's Recommendation algorithm uses filtering to narrow down the pool of all Playmate sessions to a smaller pool of sessions that only include the viable session options according to the user's preferences. Specifically, the algorithm first filters by location, only allowing the sessions that are within a certain radius of the user's origin location, and then by filtering out session of sports that the user told us they would not like to play through the quiz. Location and sport are broad categories that allow us to produce the smallest but still accurate pool of viable sessions.
Once the general filters are applied, a heuristic equation is used to assign a "ranking" to each of the viable sessions. The heuristic takes into account the quiz results, whether the user is friends with anyone in the session, and which sport and skill level sessions the user has participated in the past. The quiz results include what sports the user plays, what sports the user does not want to play, and what genders and age groups the user prefers to play sports with.
After preprocessing and calculating certain statistics for each session, the heuristic equation:
float ranking = 5.2 * sportWeight + 2.3 * numberFriendsInSession + 1.2 * numberPlayersInPreferredGenders + 1.9 * numberPlayersInPreferredAgeGroups
is used to assign a value to each session. Upon assigning a value to each of the viable session options, session are sorted and the most highly ranked sessions are displayed as suggested sessions to the user.
- This algorithm, which includes filtering and ranking, seems pretty computation heavy. When do you decide to execute this algorithm to conserve resources but also keep a user's suggested sessions up to date?
-
The recommendation system algorithm I designed is run every time after a user fills out the quiz to ensure their latest preferences are responded to as soon as possible.
-
Since the total number of sessions is not yet in the thousands, we can afford to run the algorithm every third session a user joins. However, as the app scales, we would reduce the number of times the algorithm is run to conserve resources.
-
The entire algorithm is run on a Grand Central Dispatch queue on a separate thread, so it would not interfere with processes on the main thread managing front end and other imminent tasks.
- What expansions and improvements do you have in mind for Playmate's Recommender System?
-
The user responds to each suggestion with a yes or no for whether they would attend the session and if not, the reason they would not attend the session. The algorithm would then take into account the reason and give a lower weight to sessions that share the similar trait. For example, if we suggest a session of the sport "Soccer" that is neither on the user's past history nor in their quiz preferences, and they tell us they would not attend the session because of the sport, we will adapt and remember to not suggest any Soccer sessions to this user.
-
Running the recommender system algorithm on a separate server would improve the quality of suggestions because they would be more up to date and dynamically adapt to what sessions the user is joining or creating. Also, we would be able to run the algorithm asynchonously as new sessions are created by other users, and suggest those to our users. Being able to run the algorithm on a backend server would also be useful as the number of users scale and therefore sessions increase.