best and worst stats
This commit is contained in:
@@ -24,8 +24,6 @@ struct StatsController: RouteCollection {
|
||||
statsRoute.post("logMatch", use: logMatch)
|
||||
statsRoute.get("history","page",":page", use: history)
|
||||
statsRoute.get("history", use: history)
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -82,8 +80,7 @@ struct StatsController: RouteCollection {
|
||||
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))
|
||||
return Stats( totalWins: Int(winCount), totalLosses: Int(lossCount))
|
||||
}
|
||||
|
||||
func getStatsWithMostRecentDailyRecord(matches:[Match], game:String? = nil) -> StatsWithMostRecentDailyRecord {
|
||||
@@ -109,15 +106,15 @@ struct StatsController: RouteCollection {
|
||||
self.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 {
|
||||
//
|
||||
// }
|
||||
// if game == "mw" {
|
||||
// shouldInclude = shouldInclude && match.codGame == "mw"
|
||||
// }
|
||||
// else if game == "bocw" {
|
||||
// shouldInclude = shouldInclude && match.codGame == "bocw"
|
||||
//
|
||||
// }else {
|
||||
//
|
||||
// }
|
||||
|
||||
shouldInclude = shouldInclude && match.codGame == game
|
||||
}
|
||||
@@ -260,16 +257,16 @@ struct StatsController: RouteCollection {
|
||||
// print ( Date().timeIntervalSince(startTime))
|
||||
|
||||
|
||||
// let cumulativeWinLossRatios = self.getCumulativeWinLossRatios(matches: matches)
|
||||
// let cumulativeWinLossRatios = self.getCumulativeWinLossRatios(matches: matches)
|
||||
|
||||
// print ( Date().timeIntervalSince(startTime))
|
||||
|
||||
// let highestWinLossRatio = cumulativeWinLossRatios.reduce("0") { (highestRatio, dataPoint) -> String in
|
||||
// if dataPoint.y > Double(highestRatio)!{
|
||||
// return String(dataPoint.y)
|
||||
// }
|
||||
// return highestRatio
|
||||
// }
|
||||
// let highestWinLossRatio = cumulativeWinLossRatios.reduce("0") { (highestRatio, dataPoint) -> String in
|
||||
// if dataPoint.y > Double(highestRatio)!{
|
||||
// return String(dataPoint.y)
|
||||
// }
|
||||
// return highestRatio
|
||||
// }
|
||||
// print ( Date().timeIntervalSince(startTime))
|
||||
|
||||
|
||||
@@ -356,8 +353,7 @@ struct StatsController: RouteCollection {
|
||||
let combined = winCount.and(lossCount)
|
||||
|
||||
return combined.map { (winCount, lossCount) -> (Stats) in
|
||||
let ratio:Double = (Double(winCount) / Double(lossCount)).truncate(places: 2)
|
||||
return Stats.init(winLoss: String(ratio), totalWins: winCount, totalLosses: lossCount)
|
||||
return Stats.init( totalWins: winCount, totalLosses: lossCount)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -380,7 +376,7 @@ struct StatsController: RouteCollection {
|
||||
|
||||
return combined.map { (winCount, lossCount) -> (Stats) in
|
||||
|
||||
return Stats.init(winLoss: self.getRatio(num: Double(winCount), den: Double(lossCount)), totalWins: winCount, totalLosses: lossCount)
|
||||
return Stats.init(totalWins: winCount, totalLosses: lossCount)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -403,8 +399,7 @@ struct StatsController: RouteCollection {
|
||||
let combined = winCount.and(lossCount)
|
||||
|
||||
return combined.map { (winCount, lossCount) -> (Stats) in
|
||||
let ratio:Double = (Double(winCount) / Double(lossCount)).truncate(places: 2)
|
||||
return Stats.init(winLoss: String(ratio), totalWins: winCount, totalLosses: lossCount)
|
||||
return Stats.init(totalWins: winCount, totalLosses: lossCount)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -557,7 +552,7 @@ struct StatsController: RouteCollection {
|
||||
|
||||
let hyderStats = hyderFuture.map { (withHyder, withoutHyder) -> [Stats] in
|
||||
return [withHyder, withoutHyder]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let matches = Match.query(on: req.db).all()
|
||||
@@ -597,30 +592,83 @@ struct StatsController: RouteCollection {
|
||||
|
||||
}
|
||||
|
||||
group.enter()
|
||||
queue.async {
|
||||
mostRecentStats = self.mostRecentDailyStats(matches: matches)
|
||||
group.leave()
|
||||
}
|
||||
|
||||
// group.enter()
|
||||
// queue.async {
|
||||
// mostRecentStats = self.mostRecentDailyStats(matches: matches)
|
||||
// group.leave()
|
||||
// }
|
||||
|
||||
group.wait()
|
||||
|
||||
let mapStats = getMapStats(matches: matches)
|
||||
let bestMap = getBestMap(records: mapStats)
|
||||
let worstMap = getWorstMap(records: mapStats)
|
||||
|
||||
let dashboardItems = [
|
||||
DashboardItem(title: "Overall", content: overallStats!.record, title2: "Ratio", content2: overallStats!.winLossRatio),
|
||||
DashboardItem(title: "MW Overall", content: mwStats!.record, title2: "Ratio", content2: mwStats!.winLossRatio),
|
||||
DashboardItem(title: "Cold War Overall", content: bocwStats!.record, title2: "Ratio", content2: bocwStats!.winLossRatio),
|
||||
DashboardItem(title: "With Hyder", content: hyderStats[0].record, title2: "Ratio", content2: hyderStats[0].winLossRatio),
|
||||
DashboardItem(title: "No Hyder", content: hyderStats[1].record, title2: "Ratio", content2: hyderStats[1].winLossRatio),
|
||||
DashboardItem(title: "Best Map", content: MapData.allMaps[bestMap]?.name ?? "error", title2: "Ratio", content2: "\(mapStats[bestMap]!.winLossRatio) \(mapStats[bestMap]!.record)"),
|
||||
DashboardItem(title: "Worst Map", content: MapData.allMaps[worstMap]?.name ?? "error", title2: "Ratio", content2: "\(mapStats[worstMap]!.winLossRatio) \(mapStats[worstMap]!.record)"),
|
||||
]
|
||||
|
||||
|
||||
|
||||
|
||||
return OverallStats(overall: overallStats!, mwStats: mwStats!, bocwStats: bocwStats!, mostRecentRecord: "\(mostRecentStats!.totalWins) - \(mostRecentStats!.totalLosses)", statsWithHyder:hyderStats[0], statsWithoutHyder: hyderStats[1])
|
||||
return OverallStats(overall: overallStats!, mwStats: mwStats!, bocwStats: bocwStats!, mostRecentRecord: "Temporarily Unavailable", statsWithHyder:hyderStats[0], statsWithoutHyder: hyderStats[1], dashboardItems:dashboardItems)
|
||||
}
|
||||
|
||||
|
||||
|
||||
// return Match.query(on: req.db).all().map { (matches) -> OverallStats in
|
||||
//
|
||||
//
|
||||
// }
|
||||
// return Match.query(on: req.db).all().map { (matches) -> OverallStats in
|
||||
//
|
||||
//
|
||||
// }
|
||||
}
|
||||
|
||||
func getBestMap (records :[ Int:Stats] ) -> Int {
|
||||
|
||||
let maps = records.keys.sorted { (map1, map2) -> Bool in
|
||||
return records[map1]?.getRatioDouble() ?? 0.0 < records[map2]?.getRatioDouble() ?? 0.0
|
||||
|
||||
}
|
||||
return maps.last ?? -1
|
||||
}
|
||||
|
||||
func getWorstMap (records :[ Int:Stats] ) -> Int {
|
||||
|
||||
let maps = records.keys.sorted { (map1, map2) -> Bool in
|
||||
return records[map1]?.getRatioDouble() ?? 0.0 < records[map2]?.getRatioDouble() ?? 0.0
|
||||
}
|
||||
return maps.first ?? -1
|
||||
}
|
||||
|
||||
|
||||
|
||||
func getMapStats(matches:[Match]) -> [Int:Stats] {
|
||||
var mapStats:[Int:Stats] = [Int:Stats]()
|
||||
for match in matches {
|
||||
|
||||
if match.codGame == "mw" {
|
||||
if let map = match.map, let mapInt = Int(map) {
|
||||
|
||||
if mapStats[mapInt] == nil {
|
||||
mapStats[mapInt] = Stats(totalWins: 0, totalLosses: 0)
|
||||
}
|
||||
|
||||
if match.win {
|
||||
|
||||
mapStats[mapInt]?.totalWins += 1
|
||||
}
|
||||
else{
|
||||
mapStats[mapInt]?.totalLosses += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return mapStats
|
||||
|
||||
}
|
||||
|
||||
func statsWithPlayer(req: Request, playerId:Int) -> EventLoopFuture<Stats> {
|
||||
return Match.query(on: req.db)
|
||||
@@ -629,7 +677,7 @@ struct StatsController: RouteCollection {
|
||||
return self.getStats(matches: matches)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func statsWithoutPlayer (req: Request, playerId:Int) -> EventLoopFuture<Stats> {
|
||||
return Match.query(on: req.db)
|
||||
@@ -640,19 +688,7 @@ struct StatsController: RouteCollection {
|
||||
}
|
||||
|
||||
|
||||
private func getRatio( num:Double, den:Double) -> String {
|
||||
|
||||
var returnString = ""
|
||||
let deno = (den != 0) ? den : 1
|
||||
|
||||
returnString = String((Double(num) / Double(deno)).truncate(places: 2))
|
||||
|
||||
if den == 0 {
|
||||
returnString = returnString + "+"
|
||||
}
|
||||
return returnString
|
||||
|
||||
}
|
||||
|
||||
private func getDaysPlayed(req:Request) -> EventLoopFuture<[CODDate]> {
|
||||
|
||||
@@ -722,6 +758,20 @@ struct StatsController: RouteCollection {
|
||||
}
|
||||
}
|
||||
|
||||
private func getRatio( num:Double, den:Double) -> String {
|
||||
|
||||
var returnString = ""
|
||||
let deno = (den != 0) ? den : 1
|
||||
|
||||
returnString = String((Double(num) / Double(deno)).truncate(places: 2))
|
||||
|
||||
if den == 0 {
|
||||
returnString = returnString + "+"
|
||||
}
|
||||
return returnString
|
||||
|
||||
}
|
||||
|
||||
|
||||
func getCumulativeWinLossRatios(req:Request) -> EventLoopFuture<[DataPoint]> {
|
||||
|
||||
|
||||
69
Sources/App/Data/MapData.swift
Normal file
69
Sources/App/Data/MapData.swift
Normal file
@@ -0,0 +1,69 @@
|
||||
//
|
||||
// MapData.swift
|
||||
// App
|
||||
//
|
||||
// Created by Michael Simard on 1/10/21.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class MapData {
|
||||
|
||||
|
||||
static let allMaps:[Int:Map] = [
|
||||
0: Map(id: 0, name: "Satellite", imageName: "bocw_satellite"),
|
||||
1: Map(id: 1, name: "Armada", imageName: "bocw_armada"),
|
||||
2: Map(id: 2, name: "Nuketown", imageName: "bocw_nuketown"),
|
||||
3: Map(id: 3, name: "Cartel", imageName: "bocw_cartel"),
|
||||
4: Map(id: 4, name: "Garrison", imageName: "bocw_garrison"),
|
||||
5: Map(id: 5, name: "Miami", imageName: "bocw_miami"),
|
||||
6: Map(id: 6, name: "Moscow", imageName: "bocw_moscow"),
|
||||
7: Map(id: 7, name: "Crossroads", imageName: "bocw_crossroads"),
|
||||
8: Map(id: 8, name: "Checkmate", imageName: "bocw_checkmate"),
|
||||
9: Map(id: 9, name: "Arklov Peak", imageName: "mw_arklov"),
|
||||
10: Map(id: 10, name: "Atlas Superstore", imageName: "mw_atlas"),
|
||||
11: Map(id: 11, name: "Talsik Backlot", imageName: "mw_backlot"),
|
||||
12: Map(id: 12, name: "Broadcast", imageName: "mw_broadcast"),
|
||||
13: Map(id: 13, name: "Azhir Cave", imageName: "mw_caves"),
|
||||
14: Map(id: 14, name: "Chesire Park", imageName: "mw_chesire"),
|
||||
15: Map(id: 15, name: "Crash", imageName: "mw_crash"),
|
||||
28: Map(id: 28, name: "Gun Runner", imageName: "mw_gunrunner"),
|
||||
16: Map(id: 16, name: "Hackney Yard", imageName: "mw_hackney"),
|
||||
17: Map(id: 17, name: "Suldal Harbor", imageName: "mw_harbor"),
|
||||
18: Map(id: 18, name: "Hardhat", imageName: "mw_hardhat"),
|
||||
19: Map(id: 19, name: "Hovec Sawmill", imageName: "mw_hovec"),
|
||||
20: Map(id: 20, name: "Khandor Hideout", imageName: "mw_khandor"),
|
||||
21: Map(id: 21, name: "Petrov Oil Rig", imageName: "mw_oil"),
|
||||
22: Map(id: 22, name: "St. Petrograd", imageName: "mw_petrograd"),
|
||||
23: Map(id: 23, name: "Rammaza", imageName: "mw_rammaza"),
|
||||
24: Map(id: 24, name: "Scrapyard", imageName: "mw_scrapyard"),
|
||||
25: Map(id: 25, name: "Shoot House", imageName: "mw_shoothouse"),
|
||||
26: Map(id: 26, name: "Mialstor Tank Factory", imageName: "mw_tank"),
|
||||
27: Map(id: 27, name: "Vacant", imageName: "mw_vacant"),
|
||||
31: Map(id: 31, name: "The Pines", imageName: "bocw_pines"),
|
||||
29: Map(id: 29, name: "Nuketown Holiday", imageName: "bocw_nuketown_holiday"),
|
||||
30: Map(id: 30, name: "Raid", imageName: "bocw_raid"),
|
||||
32: Map(id: 32, name: "Piccadilly", imageName: "mw_piccadilly"),
|
||||
33: Map(id: 33, name: "Grazna Raid", imageName: "mw_grazna")
|
||||
]
|
||||
|
||||
static let bocwMaps = {
|
||||
|
||||
return [1,3,8,7,4,2,29,31,5,6,30,0].compactMap {
|
||||
return allMaps[$0];
|
||||
}
|
||||
.sorted { (m1, m2) -> Bool in
|
||||
return m1.name < m2.name
|
||||
}
|
||||
}
|
||||
static let mwMaps = {
|
||||
return [9,10,11,12,13,14,15,28,16,17,18,19,20,21,22,23,24,25,26,27,32,33].compactMap {
|
||||
return allMaps[$0];
|
||||
}.sorted { (m1, m2) -> Bool in
|
||||
return m1.name < m2.name
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -50,8 +50,9 @@ final class OverallStats: Content {
|
||||
var statsWithHyder:Stats
|
||||
var statsWithoutHyder:Stats
|
||||
|
||||
var dashboardItems:[DashboardItem] = []
|
||||
|
||||
init( overall:StatsWithMostRecentDailyRecord, mwStats:StatsWithMostRecentDailyRecord, bocwStats:StatsWithMostRecentDailyRecord, mostRecentRecord:String, statsWithHyder:Stats, statsWithoutHyder:Stats){
|
||||
init( overall:StatsWithMostRecentDailyRecord, mwStats:StatsWithMostRecentDailyRecord, bocwStats:StatsWithMostRecentDailyRecord, mostRecentRecord:String, statsWithHyder:Stats, statsWithoutHyder:Stats, dashboardItems:[DashboardItem]){
|
||||
|
||||
self.overall = overall
|
||||
self.mwStats = mwStats;
|
||||
@@ -60,6 +61,8 @@ final class OverallStats: Content {
|
||||
|
||||
self.statsWithHyder = statsWithHyder
|
||||
self.statsWithoutHyder = statsWithoutHyder
|
||||
|
||||
self.dashboardItems = dashboardItems
|
||||
}
|
||||
|
||||
}
|
||||
@@ -81,15 +84,39 @@ final class MonthStats: Content {
|
||||
|
||||
|
||||
final class Stats: Content {
|
||||
var winLossRatio:String
|
||||
|
||||
var winLossRatio:String {
|
||||
get {
|
||||
return getRatio()
|
||||
}
|
||||
}
|
||||
var totalWins:Int
|
||||
var totalLosses:Int
|
||||
|
||||
init( winLoss:String, totalWins:Int, totalLosses:Int) {
|
||||
self.winLossRatio = winLoss
|
||||
init( totalWins:Int, totalLosses:Int) {
|
||||
self.totalWins = totalWins
|
||||
self.totalLosses = totalLosses
|
||||
}
|
||||
|
||||
var record:String {
|
||||
return "\(totalWins)-\(totalLosses)"
|
||||
}
|
||||
|
||||
private func getRatio() -> String {
|
||||
var returnString = ""
|
||||
let deno = (totalLosses != 0) ? totalLosses : 1
|
||||
returnString = String(getRatioDouble())
|
||||
if deno == 0 {
|
||||
returnString = returnString + "+"
|
||||
}
|
||||
return returnString
|
||||
}
|
||||
|
||||
func getRatioDouble() -> Double {
|
||||
let deno = (totalLosses != 0) ? totalLosses : 1
|
||||
|
||||
return (Double(totalWins) / Double(deno)).truncate(places: 3)
|
||||
}
|
||||
}
|
||||
|
||||
final class StatsWithMostRecentDailyRecord: Content {
|
||||
@@ -104,6 +131,10 @@ final class StatsWithMostRecentDailyRecord: Content {
|
||||
self.totalLosses = totalLosses
|
||||
self.mostRecentRecord = mostRecentRecord
|
||||
}
|
||||
|
||||
var record:String {
|
||||
return "\(totalWins)-\(totalLosses)"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
19
Sources/App/Models/DashboardItem.swift
Normal file
19
Sources/App/Models/DashboardItem.swift
Normal file
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// DashboardItem.swift
|
||||
// App
|
||||
//
|
||||
// Created by Michael Simard on 1/9/21.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Fluent
|
||||
import Vapor
|
||||
|
||||
struct DashboardItem: Content {
|
||||
var title:String
|
||||
var content:String
|
||||
var title2:String? = nil
|
||||
var content2:String? = nil
|
||||
|
||||
|
||||
}
|
||||
16
Sources/App/Models/Map.swift
Normal file
16
Sources/App/Models/Map.swift
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// Map.swift
|
||||
// App
|
||||
//
|
||||
// Created by Michael Simard on 1/10/21.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct Map: Hashable {
|
||||
var id: Int
|
||||
var name:String
|
||||
var imageName:String
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user