diff --git a/Sources/App/Controllers/StatsController.swift b/Sources/App/Controllers/StatsController.swift index 7e07a62..6baf3e1 100644 --- a/Sources/App/Controllers/StatsController.swift +++ b/Sources/App/Controllers/StatsController.swift @@ -22,24 +22,22 @@ struct StatsController: RouteCollection { statsRoute.get("allDaily", use: allDaily) statsRoute.get("test", use: test) statsRoute.post("logMatch", use: logMatch) - - statsRoute.get("history","page",":page", use: history) statsRoute.get("history", use: history) } - + func history(req: Request) throws -> EventLoopFuture { if let page = req.parameters.get("page", as: Int.self) { return Match.query(on: req.db).count().flatMap { (totalMatches) -> EventLoopFuture in - + let startRecord = min (page * 20, totalMatches) let lastRecord = min (startRecord + 20, totalMatches) - + return Match.query(on: req.db).sort(\.$date, .descending).range(startRecord.. (MatchHistory) in return MatchHistory(total:totalMatches, matches: matches, hasMorePages: lastRecord < totalMatches) @@ -52,12 +50,12 @@ struct StatsController: RouteCollection { return Match.query(on: req.db).count().flatMap { (totalMatches) -> EventLoopFuture in return Match.query(on: req.db).sort(\.$date, .descending).limit(20).all().map { (matches) -> (MatchHistory) in return MatchHistory(total:totalMatches, matches: matches, hasMorePages: totalMatches > 20) - + } } } - + } @@ -65,13 +63,16 @@ struct StatsController: RouteCollection { let newMatch = try req.content.decode(Match.self) - return newMatch.save(on: req.db).map { newMatch} + return newMatch.save(on: req.db).map { newMatch} } func getStats(matches:[Match]) -> Stats{ - - let totals = matches.reduce([0,0]) { (totals, match) -> [Int] in + let countedMatches = matches.filter { + return shouldCountMatch(match: $0) + } + + let totals = countedMatches.reduce([0,0]) { (totals, match) -> [Int] in if match.win == true { return [totals[0] + 1, totals[1]] @@ -80,44 +81,70 @@ struct StatsController: RouteCollection { return [totals[0], totals[1] + 1] } } -// for match in matches { -// if match.win == true { -// winCount += 1; -// -// } -// if match.win == false { -// lossCount += 1; -// } -// } - let winCount = totals[0] let lossCount = totals[1] - let ratio = self.getRatio(num: Double(winCount), den: Double(lossCount)) - return Stats(winLoss: ratio, totalWins: Int(winCount), totalLosses: Int(lossCount)) } - + + func getStatsWithMostRecentDailyRecord(matches:[Match], game:String? = nil) -> StatsWithMostRecentDailyRecord { + + let stats = getStats(matches: matches) + let mostRecentDailyStats = self.mostRecentDailyStats(matches: matches, game: game) + + let ret = StatsWithMostRecentDailyRecord(winLoss: stats.winLossRatio, totalWins: stats.totalWins, totalLosses: stats.totalLosses, mostRecentRecord:"\(mostRecentDailyStats.totalWins)-\(mostRecentDailyStats.totalLosses)") + + return ret + } - func mostRecentDailyStats (matches:[Match]) -> Stats{ - + func mostRecentDailyStats (matches:[Match], game:String? = nil) -> Stats{ + let daysPlayed = getDaysPlayed(matches: matches) let lastDayPlayed = daysPlayed.last return getStats(matches: matches.filter({ (match) -> Bool in - return + var shouldInclude = match.date.day == lastDayPlayed?.day && match.date.month == lastDayPlayed?.month && - match.date.year == lastDayPlayed?.year - + match.date.year == lastDayPlayed?.year && + shouldCountMatch(match: match) + + if let game = game { +// if game == "mw" { +// shouldInclude = shouldInclude && match.codGame == "mw" +// } +// else if game == "bocw" { +// shouldInclude = shouldInclude && match.codGame == "bocw" +// +// }else { +// +// } + + shouldInclude = shouldInclude && match.codGame == game + } + + + return shouldInclude })) - - } + + private func shouldCountMatch (match:Match) -> Bool { + let isColdWar = match.codGame == "bocw" + let numberOfPlayers = self.numberOfPlayers(match: match) + + return !isColdWar || (isColdWar && (numberOfPlayers == 0 || numberOfPlayers > 4 )) + } + + + + private func numberOfPlayers(match:Match) -> Int { + return match.players?.components(separatedBy: ",").count ?? 0 + } + private func getDaysPlayed(matches:[Match]) -> [CODDate] { var sortedMatches = matches @@ -146,14 +173,9 @@ struct StatsController: RouteCollection { func getCumulativeWinLossRatios(matches:[Match]) -> [DataPoint] { - - let startTime = Date() - -//print ("c \(Date().timeIntervalSince(startTime))") - + let daysPlayed = getDaysPlayed(matches: matches) - // print ("c \(Date().timeIntervalSince(startTime))") - + var cumulativeRatios : [DataPoint] = [] var cumulativeWins:Int = 0 var cumulativeLosses:Int = 0 @@ -163,13 +185,13 @@ struct StatsController: RouteCollection { var currentDay = daysPlayed.first?.day ?? 0 var currentMonth = daysPlayed.first?.month ?? 0 var currentYear = daysPlayed.first?.year ?? 0 - + let sortedMatches = matches.sorted { (m1, m2) -> Bool in return m1.date < m2.date } - + var currentMatches:[Match] = [] - + for match in sortedMatches { if match.date.year == currentYear && match.date.month == currentMonth && match.date.day == currentDay { currentMatches.append(match) @@ -187,33 +209,13 @@ struct StatsController: RouteCollection { let stats = self.getStats(matches: matchGroup) - + cumulativeWins = cumulativeWins + stats.totalWins; cumulativeLosses = cumulativeLosses + stats.totalLosses; cumulativeRatios.append( DataPoint(x: Double(i), y: (Double(cumulativeWins) / (Double(cumulativeLosses) )), label: ("\(Utilities.monthToString(month: matchGroup.first!.date.month)) \( matchGroup.first!.date.day)"))) } -// for (i, day) in daysPlayed.enumerated() { -// print ("ca \(Date().timeIntervalSince(startTime))") -// -// -// let stats = self.getStats(matches: matches.filter({ (match) -> Bool in -// return match.date.day == day.day && match.date.year == day.year && match.date.month == day.month -// })) -// -// print ("cb \(Date().timeIntervalSince(startTime))") -// -// cumulativeWins = cumulativeWins + stats.totalWins; -// cumulativeLosses = cumulativeLosses + stats.totalLosses; -// cumulativeRatios.append( DataPoint(x: Double(i), y: (Double(cumulativeWins) / (Double(cumulativeLosses) )), label: ("\(Utilities.monthToString(month: day.month)) \(day.day)"))) -// -// print ("cc \(Date().timeIntervalSince(startTime))") -// -// } - // print ("c \(Date().timeIntervalSince(startTime))") - - return cumulativeRatios } @@ -221,34 +223,36 @@ struct StatsController: RouteCollection { func test(req: Request) throws -> EventLoopFuture { let startTime = Date() - + var date = getStartDate() var previousMonths:[CODDate] = [] - + repeat { //let stats = getStatsByMonth(year: date.year, month: date.month, req: req) //returns eventloopfuture previousMonths.append(CODDate(month: date.month, year: date.year, day: 15, hour:6, minute: 0)) date = Calendar.current.date(byAdding: .month, value: 1, to: date)! } while ( date < Calendar.current.date(byAdding: .month, value: 1, to: Date())!) - // print (date - Date().timeIntervalSince(startTime)) + // print (date - Date().timeIntervalSince(startTime)) return Match.query(on: req.db).all().map { (matches) -> AllStats in - let overallStats = self.getStats(matches: matches) - // print ( Date().timeIntervalSince(startTime)) - - let mwStats = self.getStats(matches: matches.filter({ (match) -> Bool in + let overallStats = self.getStatsWithMostRecentDailyRecord(matches: matches) + // print ( Date().timeIntervalSince(startTime)) + + let mwStats = self.getStatsWithMostRecentDailyRecord(matches: matches.filter({ (match) -> Bool in return match.codGame == "mw" })) - // print ( Date().timeIntervalSince(startTime)) - - let bocwStats = self.getStats(matches: matches.filter({ (match) -> Bool in + // print ( Date().timeIntervalSince(startTime)) + + let bocwStats = self.getStatsWithMostRecentDailyRecord(matches: matches.filter({ (match) -> Bool in return match.codGame == "bocw" })) - // print ( Date().timeIntervalSince(startTime)) - + // print ( Date().timeIntervalSince(startTime)) + + + let mostRecentDailyStats = self.mostRecentDailyStats(matches: matches) - + let monthlyStats = previousMonths.reversed().map { (codDate) -> MonthStats in let relevantMatches = matches.filter { (match) -> Bool in @@ -256,22 +260,22 @@ struct StatsController: RouteCollection { } return MonthStats(month: codDate.month, year: codDate.year, stats: self.getStats(matches: relevantMatches )) } - // print ( Date().timeIntervalSince(startTime)) - + // print ( Date().timeIntervalSince(startTime)) + let cumulativeWinLossRatios = self.getCumulativeWinLossRatios(matches: matches) - // print ( Date().timeIntervalSince(startTime)) - + // print ( Date().timeIntervalSince(startTime)) + let highestWinLossRatio = cumulativeWinLossRatios.reduce("0") { (highestRatio, dataPoint) -> String in - if dataPoint.y > Double(highestRatio)!{ - return String(dataPoint.y) - } - return highestRatio + if dataPoint.y > Double(highestRatio)!{ + return String(dataPoint.y) + } + return highestRatio } - // print ( Date().timeIntervalSince(startTime)) - - + // print ( Date().timeIntervalSince(startTime)) + + return AllStats.init(overall: overallStats,mwStats: mwStats, bocwStats: bocwStats, byMonth: monthlyStats, highestWinLossRatio: highestWinLossRatio, dataPoints: cumulativeWinLossRatios, mostRecentRecord: "\(mostRecentDailyStats.totalWins) - \(mostRecentDailyStats.totalLosses)") } @@ -319,7 +323,7 @@ struct StatsController: RouteCollection { return Match.query(on: req.db).sort(\.$date).all() } - + func totalWins(req: Request) throws -> EventLoopFuture { return Match.query(on: req.db) @@ -495,67 +499,67 @@ struct StatsController: RouteCollection { -// func all(req: Request) throws -> EventLoopFuture { -// -// var date = getStartDate() -// var previousMonths:[CODDate] = [] -// -// repeat { -// //let stats = getStatsByMonth(year: date.year, month: date.month, req: req) //returns eventloopfuture -// previousMonths.append(CODDate(month: date.month, year: date.year, day: 15, hour:6, minute: 0)) -// date = Calendar.current.date(byAdding: .month, value: 1, to: date)! -// }while ( date < Calendar.current.date(byAdding: .month, value: 1, to: Date())!) -// -// -// func getMonthStats (_ remaining: ArraySlice, allMonthlyStats: inout [MonthStats], eventLoop: EventLoop) -> EventLoopFuture<[MonthStats]> { -// var remaining = remaining -// if let first = remaining.popLast() { -// -// return getstatsForMonth(year: first.year, month: first.month, req: req).flatMap { [remaining, allMonthlyStats] (stats) -> EventLoopFuture<[MonthStats]> in -// var allMonthlyStats = allMonthlyStats -// allMonthlyStats.append(MonthStats(month: first.month, year: first.year, stats:stats )) -// return getMonthStats(remaining, allMonthlyStats:&allMonthlyStats, eventLoop: eventLoop) -// } -// -// } else { -// return req.eventLoop.makeSucceededFuture(allMonthlyStats) -// } -// } -// -// var stats:[MonthStats] = [] -// let monthstats = getMonthStats(previousMonths[0.. AllStats in -// -// let (((overall, monthlyStats), cumulativeRatios), mostRecentDayStats) = arg -// let highestWinLossRatio = cumulativeRatios.reduce("0") { (highestRatio, dataPoint) -> String in -// if dataPoint.y > Double(highestRatio)!{ -// return String(dataPoint.y) -// } -// return highestRatio -// } -// -// -// return AllStats.init(overall: overall,mwStats: overall, bocwStats: overall, byMonth: monthlyStats, highestWinLossRatio: highestWinLossRatio, dataPoints: cumulativeRatios, mostRecentRecord: "\(mostRecentDayStats.totalWins) - \(mostRecentDayStats.totalLosses)") -// } -// } -// + // func all(req: Request) throws -> EventLoopFuture { + // + // var date = getStartDate() + // var previousMonths:[CODDate] = [] + // + // repeat { + // //let stats = getStatsByMonth(year: date.year, month: date.month, req: req) //returns eventloopfuture + // previousMonths.append(CODDate(month: date.month, year: date.year, day: 15, hour:6, minute: 0)) + // date = Calendar.current.date(byAdding: .month, value: 1, to: date)! + // }while ( date < Calendar.current.date(byAdding: .month, value: 1, to: Date())!) + // + // + // func getMonthStats (_ remaining: ArraySlice, allMonthlyStats: inout [MonthStats], eventLoop: EventLoop) -> EventLoopFuture<[MonthStats]> { + // var remaining = remaining + // if let first = remaining.popLast() { + // + // return getstatsForMonth(year: first.year, month: first.month, req: req).flatMap { [remaining, allMonthlyStats] (stats) -> EventLoopFuture<[MonthStats]> in + // var allMonthlyStats = allMonthlyStats + // allMonthlyStats.append(MonthStats(month: first.month, year: first.year, stats:stats )) + // return getMonthStats(remaining, allMonthlyStats:&allMonthlyStats, eventLoop: eventLoop) + // } + // + // } else { + // return req.eventLoop.makeSucceededFuture(allMonthlyStats) + // } + // } + // + // var stats:[MonthStats] = [] + // let monthstats = getMonthStats(previousMonths[0.. AllStats in + // + // let (((overall, monthlyStats), cumulativeRatios), mostRecentDayStats) = arg + // let highestWinLossRatio = cumulativeRatios.reduce("0") { (highestRatio, dataPoint) -> String in + // if dataPoint.y > Double(highestRatio)!{ + // return String(dataPoint.y) + // } + // return highestRatio + // } + // + // + // return AllStats.init(overall: overall,mwStats: overall, bocwStats: overall, byMonth: monthlyStats, highestWinLossRatio: highestWinLossRatio, dataPoints: cumulativeRatios, mostRecentRecord: "\(mostRecentDayStats.totalWins) - \(mostRecentDayStats.totalLosses)") + // } + // } + // func overall(req: Request) throws -> EventLoopFuture { return Match.query(on: req.db).all().map { (matches) -> OverallStats in - let overallStats = self.getStats(matches: matches) - // print ( Date().timeIntervalSince(startTime)) - - let mwStats = self.getStats(matches: matches.filter({ (match) -> Bool in - return match.codGame == "mw" + let overallStats = self.getStatsWithMostRecentDailyRecord(matches: matches) + // print ( Date().timeIntervalSince(startTime)) + + let mwStats = self.getStatsWithMostRecentDailyRecord(matches: matches.filter({ (match) -> Bool in + return match.codGame == "mw" && shouldCountMatch(match: match ) })) - - let bocwStats = self.getStats(matches: matches.filter({ (match) -> Bool in - return match.codGame == "bocw" + + let bocwStats = self.getStatsWithMostRecentDailyRecord(matches: matches.filter({ (match) -> Bool in + return match.codGame == "bocw" && shouldCountMatch(match: match ) })) let mostRecentDailyStats = self.mostRecentDailyStats(matches: matches) @@ -673,7 +677,7 @@ struct StatsController: RouteCollection { if !(stats.totalWins == 0 && stats.totalLosses == 0) { let date = self.createDate(day: first.day, month: first.month, year: first.year, hour: first.hour + 6, minute:first.minute) // 6 hours to make sure we pick a time that isnt on borders of us time zones - // print ("p \(date.timeIntervalSince1970)") + // print ("p \(date.timeIntervalSince1970)") let x = Double(cumulativeWinLossRatios.count) let d = Date(timeIntervalSince1970: date.timeIntervalSince1970) @@ -749,5 +753,5 @@ extension Date { } - + } diff --git a/Sources/App/Models/AllStats.swift b/Sources/App/Models/AllStats.swift index e17e91e..485b704 100644 --- a/Sources/App/Models/AllStats.swift +++ b/Sources/App/Models/AllStats.swift @@ -25,15 +25,15 @@ struct DataPoint : Content { final class AllStats: Content { - var overall:Stats - var mwStats:Stats - var bocwStats:Stats + var overall:StatsWithMostRecentDailyRecord + var mwStats:StatsWithMostRecentDailyRecord + var bocwStats:StatsWithMostRecentDailyRecord var byMonth: [MonthStats] var highestWinLossRatio:String var dataPoints:[DataPoint] var mostRecentRecord:String - init( overall:Stats, mwStats:Stats, bocwStats:Stats, byMonth:[MonthStats], highestWinLossRatio:String, dataPoints:[DataPoint], mostRecentRecord:String) { + init( overall:StatsWithMostRecentDailyRecord, mwStats:StatsWithMostRecentDailyRecord, bocwStats:StatsWithMostRecentDailyRecord, byMonth:[MonthStats], highestWinLossRatio:String, dataPoints:[DataPoint], mostRecentRecord:String) { self.overall = overall self.byMonth = byMonth self.highestWinLossRatio = highestWinLossRatio @@ -46,12 +46,12 @@ final class AllStats: Content { } final class OverallStats: Content { - var overall:Stats - var mwStats:Stats - var bocwStats:Stats + var overall:StatsWithMostRecentDailyRecord + var mwStats:StatsWithMostRecentDailyRecord + var bocwStats:StatsWithMostRecentDailyRecord var mostRecentRecord:String - init( overall:Stats, mwStats:Stats, bocwStats:Stats, mostRecentRecord:String){ + init( overall:StatsWithMostRecentDailyRecord, mwStats:StatsWithMostRecentDailyRecord, bocwStats:StatsWithMostRecentDailyRecord, mostRecentRecord:String){ self.overall = overall self.mwStats = mwStats; @@ -77,6 +77,7 @@ final class MonthStats: Content { } + final class Stats: Content { var winLossRatio:String var totalWins:Int @@ -86,10 +87,25 @@ final class Stats: Content { self.winLossRatio = winLoss self.totalWins = totalWins self.totalLosses = totalLosses - } } +final class StatsWithMostRecentDailyRecord: Content { + var winLossRatio:String + var totalWins:Int + var totalLosses:Int + var mostRecentRecord:String + + init( winLoss:String, totalWins:Int, totalLosses:Int, mostRecentRecord:String ) { + self.winLossRatio = winLoss + self.totalWins = totalWins + self.totalLosses = totalLosses + self.mostRecentRecord = mostRecentRecord + } +} + + + final class AllDailyStats: Content { var dailyStats : [DailyStats]