def possibleSequencesBWStartTimeAndEndPoint(listOfPoints, visitedPoints, currentSequence, endPoint, endPointEnterTime, endPointExitTime, startTime, weekDay): possibleSequences = [] for index, startPoint in enumerate(listOfPoints): pointName = startPoint['pointName'] if pointName not in visitedPoints: visitingTimeOfPoint = roundUpTime( float(startPoint['recommendedNumHours'])) travelTimeToEndPoint = getTravelTime(startPoint, endPoint) pointEnterTime = roundUpTime(startTime) pointExitTime = roundUpTime(pointEnterTime + visitingTimeOfPoint) pointEnterTimeBasedOnOpeningHour = getEnterTimeBasedOnOpeningHour( startPoint, pointEnterTime, pointExitTime, weekDay) if pointEnterTimeBasedOnOpeningHour < 0: continue else: pointEnterTime = roundUpTime(pointEnterTimeBasedOnOpeningHour) pointExitTime = roundUpTime(pointEnterTime + visitingTimeOfPoint) if pointExitTime + travelTimeToEndPoint <= endPointEnterTime: visitedListForPoint = visitedPoints.copy() visitedListForPoint[pointName] = 1 sequenceForPoint = currentSequence[:] pointInSeqFormat = { 'point': startPoint, 'enterTime': pointEnterTime, 'exitTime': pointExitTime } sequenceForPoint.append(pointInSeqFormat) # this will add all possible sequence which end with endPoint and have some points in starting possibleSequencesBWStartAndEndPoint( listOfPoints=listOfPoints, visitedPoints=visitedListForPoint, startPoint=startPoint, startPointExitTIme=pointExitTime, endPoint=endPoint, endPointEnterTime=endPointEnterTime, endPointExitTime=endPointExitTime, currentSequence=sequenceForPoint, weekDay=weekDay, possibleSequences=possibleSequences) # we also need to add only endPoint no any other points pointInSeqFormat = { 'point': endPoint, 'enterTime': endPointEnterTime, 'exitTime': endPointExitTime } sequenceForOnlyEndPoint = [pointInSeqFormat] possibleSequences.append(sequenceForOnlyEndPoint) return possibleSequences
def possibleSequencesBWStartPointAndEndTime(listOfPoints, visitedPoints, startPoint, currentSequence, startPointExitTime, endTime, weekDay, possibleSequences): possibleSequences.append(currentSequence) for index, point in enumerate(listOfPoints): pointName = point['pointName'] if pointName not in visitedPoints: travelTime = getTravelTime(startPoint, point) visitingTime = roundUpTime(float(point['recommendedNumHours'])) pointEnterTime = roundUpTime(startPointExitTime + travelTime) pointExitTime = roundUpTime(pointEnterTime + visitingTime) pointEnterTimeBasedOnOpeningHour = getEnterTimeBasedOnOpeningHour( point, pointEnterTime, pointExitTime, weekDay) if pointEnterTimeBasedOnOpeningHour < 0: continue else: pointEnterTime = roundUpTime(pointEnterTimeBasedOnOpeningHour) pointExitTime = roundUpTime(pointEnterTime + visitingTime) if pointExitTime <= endTime: visitedListForPoint = visitedPoints.copy() visitedListForPoint[pointName] = 1 sequenceForPoint = currentSequence[:] pointInSeqFormat = { 'point': point, 'enterTime': pointEnterTime, 'exitTime': pointExitTime } sequenceForPoint.append(pointInSeqFormat) possibleSequencesBWStartPointAndEndTime( listOfPoints=listOfPoints, visitedPoints=visitedListForPoint, startPoint=point, currentSequence=sequenceForPoint, startPointExitTime=pointExitTime, endTime=endTime, weekDay=weekDay, possibleSequences=possibleSequences)
def getTravelTime(point1, point2): distance = getDistance(point1, point2) return roundUpTime(distance / avgSpeedOfTravel) # assumed avg speed 40km/hr
def getDayItinerary(listOfPoints, mustVisitPoints, mustVisitPlaceEnterExitTime, dayStartTime, dayEndTime, weekDay, pFactor): possibleSequences = [] visitedPoints = {} if len(mustVisitPoints) == 0: # we can choose any start point for index, startPoint in enumerate(listOfPoints): pointName = startPoint['pointName'] startPointEnterTime = roundUpTime(dayStartTime) startPointVisitingTime = roundUpTime( float(startPoint['recommendedNumHours'])) startPointExitTime = roundUpTime(startPointEnterTime + startPointVisitingTime) pointEnterTimeBasedOnOpeningHour = getEnterTimeBasedOnOpeningHour( startPoint, startPointEnterTime, startPointExitTime, weekDay) if pointEnterTimeBasedOnOpeningHour < 0: continue else: startPointEnterTime = roundUpTime( pointEnterTimeBasedOnOpeningHour) startPointExitTime = roundUpTime(startPointEnterTime + startPointVisitingTime) if startPointExitTime <= dayEndTime: visitedPointsForStartPoint = visitedPoints.copy() visitedPointsForStartPoint[pointName] = 1 currentSequence = [{ 'point': startPoint, 'enterTime': startPointEnterTime, 'exitTime': startPointExitTime }] possibleSequencesBWStartPointAndEndTime( listOfPoints=listOfPoints, visitedPoints=visitedPointsForStartPoint, startPoint=startPoint, currentSequence=currentSequence, startPointExitTime=startPointExitTime, endTime=dayEndTime, weekDay=weekDay, possibleSequences=possibleSequences) else: # points can be added before first must visit point, if it is not possible to add points before first must visit point this function will add only # first must visit point in possibleSequences firstPointEnterTime = mustVisitPlaceEnterExitTime[0][0] firstPointExitTime = mustVisitPlaceEnterExitTime[0][1] endPoint = mustVisitPoints[0] possibleSequences = possibleSequencesBWStartTimeAndEndPoint( listOfPoints=listOfPoints, visitedPoints=visitedPoints, currentSequence=[], endPoint=endPoint, endPointEnterTime=firstPointEnterTime, endPointExitTime=firstPointExitTime, startTime=dayStartTime, weekDay=weekDay) for index, startPoint in enumerate(mustVisitPoints): startPointExitTime = mustVisitPlaceEnterExitTime[index][ 1] # end Time will be now start time for sequence possibleSequencesAfterIter = [ ] # each iteration of loop will create new possible sequence based on previous iteration possibleSequences if index < len( mustVisitPoints ) - 1: # for this we have start point and end point always for sequence in possibleSequences: visitedPointsForSeq = visitedPoints.copy() for seqData in sequence: visitedPointsForSeq[seqData['point']['pointName']] = 1 endPoint = mustVisitPoints[index + 1] endPointEnterTime = mustVisitPlaceEnterExitTime[index + 1][0] endPointExitTime = mustVisitPlaceEnterExitTime[index + 1][1] possibleSequencesBWStartAndEndPoint( listOfPoints=listOfPoints, visitedPoints=visitedPointsForSeq, startPoint=startPoint, startPointExitTIme=startPointExitTime, endPoint=endPoint, endPointEnterTime=endPointEnterTime, endPointExitTime=endPointExitTime, currentSequence=sequence, weekDay=weekDay, possibleSequences=possibleSequencesAfterIter) else: for sequence in possibleSequences: visitedPointsForSeq = visitedPoints.copy() for seqData in sequence: visitedPointsForSeq[seqData['point']['pointName']] = 1 possibleSequencesBWStartPointAndEndTime( listOfPoints=listOfPoints, visitedPoints=visitedPointsForSeq, startPoint=startPoint, currentSequence=sequence, startPointExitTime=startPointExitTime, endTime=dayEndTime, weekDay=weekDay, possibleSequences=possibleSequencesAfterIter) possibleSequences = possibleSequencesAfterIter[:] bestSequence = getBestSequence(possibleSequences, pFactor) # for sequence in possibleSequences: # print('gScore: ', gratificationScoreOfSequence([seqData['point'] for seqData in sequence], pFactor)) # for seqData in sequence: # print(seqData['point']['pointName']) # print() return bestSequence
def validateLikes(): cityName = clientDefaultCity cityName = request.args.get('city', cityName) if cityName: cityName = urlDecode(cityName) strFormat = '%y/%m/%d' startDate = datetime.datetime.now().strftime(strFormat) endDate = (datetime.datetime.now() + datetime.timedelta(days=clientDefaultTripLength - 1)).strftime(strFormat) startDayTime, endDayTime = clientDefaultStartTime, clientDefaultEndTime startDate = request.args.get('startDate', startDate) endDate = request.args.get('endDate', endDate) startDayTime = float(request.args.get('startDayTime', startDayTime)) endDayTime = float(request.args.get('endDayTime', endDayTime)) numDays = getNumDays(startDate, endDate) likes = request.args.get('likes', []) likesTimings = request.args.get('likesTimings', []) mustVisit = {dayNum: [] for dayNum in range(1, numDays + 1)} if likes and likesTimings: likes = list(map(urlDecode, likes.split('|'))) likesTimings = list(map(urlDecode, likesTimings.split('|'))) for pointName, timing in zip(likes, likesTimings): dayNum, enterTime, exitTime = map(float, timing.split('-')) if dayNum not in mustVisit: return 'Invalid day number {}'.format(int(dayNum)) mustVisit[dayNum].append((enterTime, exitTime, pointName)) for dayNum in mustVisit: mustVisit[dayNum] = list(sorted(mustVisit[dayNum])) dislikes = request.args.get('dislikes', []) if dislikes: dislikes = set(map(urlDecode, dislikes.split('|'))) start = datetime.datetime(*list(map(int, startDate.strip().split('/')))) today = start weekDay = (today.weekday() + 1) % 7 weekDays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'] pointMap = getTopPointsOfCity(cityName, 100)['points'] for dayNum, visits in mustVisit.items(): previousPoint = None previousExitTime = None for enterTime, exitTime, pointName in visits: if pointName in dislikes: return 'You\'ve asked us not to show {}'.format(pointName) point = pointMap[pointName] if 'openingHour' not in point or 'closingHour' not in point: continue opening = point['openingHour'].split(',')[weekDay] closing = point['closingHour'].split(',')[weekDay] if opening == '$' or closing == '$': return '{} is closed on the day {} of your plan'.format(point['pointName'], dayNum) opening = float(opening) closing = float(closing) if not (opening <= enterTime < exitTime <= closing): return 'Unacceptable enter and exit time. {} is open from {} to {} on {}'.format( point['pointName'], opening, closing, weekDays[weekDay] ) if previousPoint: travelTime = latlngDistance(*previousPoint['coordinates'].split(','), *point['coordinates'].split(',')) / avgSpeedOfTravel travelTime = roundUpTime(travelTime) if previousExitTime + travelTime > enterTime: return 'It takes {} hours to travel from {} to {}. You can\'t exit {} at {} and enter {} at {}'.format( travelTime, previousPoint['pointName'], point['pointName'], previousPoint['pointName'], previousExitTime, point['pointName'], enterTime ) previousPoint = point previousExitTime = exitTime weekDay = (weekDay + 1) % 7 return 'success'