|
| 1 | +import java.util.Date |
| 2 | + |
| 3 | +/** |
| 4 | + * Defines the needed datastructures to represent the worlcup |
| 5 | + */ |
| 6 | + |
| 7 | +object Data { |
| 8 | + def main(args: Array[String]){ |
| 9 | + //getAllGames |
| 10 | + //getAllTeams |
| 11 | + val start = System.currentTimeMillis() |
| 12 | + val aha = Group.allGroups |
| 13 | + |
| 14 | + println(s"${Match.playedMatches.length}") |
| 15 | + println(s"${Player.allPlayers(0).results}") |
| 16 | + |
| 17 | + println(s"It took: ${System.currentTimeMillis() - start} ms ") |
| 18 | + } |
| 19 | +} |
| 20 | + |
| 21 | +case class Team(name: String, id: Int, group: Char, iconUrl: String){ |
| 22 | + override def toString = s"($name, $group)" |
| 23 | +} |
| 24 | + |
| 25 | +object Team { |
| 26 | + val allTeams: List[Team] = Retrieval.getAllTeams |
| 27 | +} |
| 28 | + |
| 29 | +case class Group(name: Char, |
| 30 | + teams: Set[Team], |
| 31 | + games: List[Match] |
| 32 | +) |
| 33 | + |
| 34 | +object Group { |
| 35 | + lazy val allGroups: List[Group] = { |
| 36 | + val mapping = Team.allTeams.groupBy(_.group) |
| 37 | + (for{ |
| 38 | + groupName <- mapping.keys |
| 39 | + } yield new Group(groupName, |
| 40 | + mapping(groupName).toSet, |
| 41 | + Match.allMatches.filter(_.group == groupName))).toList.sortBy(_.name) |
| 42 | + } |
| 43 | +} |
| 44 | + |
| 45 | + |
| 46 | +case class Match(teamA: String, |
| 47 | + teamAId: Int, |
| 48 | + teamB: String, |
| 49 | + teamBId: Int, |
| 50 | + group: Char, |
| 51 | + date: java.util.Date, |
| 52 | + location: String, |
| 53 | + locationId: Int, |
| 54 | + stadium: String, |
| 55 | + id : Int, |
| 56 | + groupId: Int, |
| 57 | + groupOrderId: Int, |
| 58 | + groupName: String, |
| 59 | + scoreA: Int, |
| 60 | + scoreB: Int, |
| 61 | + isFinished: Boolean = false) { |
| 62 | + |
| 63 | + //override def toString = s"$teamA vs $teamB on the $date at $location has result: $scoreA:$scoreB" |
| 64 | +} |
| 65 | + |
| 66 | +object Match { |
| 67 | + lazy val allMatches: List[Match] = Retrieval.getAllGamesVorrunde.sortBy(_.group) |
| 68 | + lazy val playedMatches: List[Match] = allMatches.filter(_.isFinished).sortBy(_.date) |
| 69 | +} |
| 70 | + |
| 71 | +case class Tipp(matchId: Int, playerId: String, scoreA: Int, scoreB: Int) |
| 72 | + |
| 73 | +object Tipp{ |
| 74 | + |
| 75 | + //returns a time-series of points |
| 76 | + def evaluateTipps(tipps: List[Tipp], playerId: String): Stats = { |
| 77 | + var points = 0 |
| 78 | + var tendencies = 0 |
| 79 | + var diffs = 0 |
| 80 | + var hits = 0 |
| 81 | + var falseTipps = 0 |
| 82 | + var missed = 0 |
| 83 | + |
| 84 | + var pointsTime = List[(Date, Int)]() |
| 85 | + var tendenciesTime = List[(Date, Int)]() |
| 86 | + var diffsTime = List[(Date, Int)]() |
| 87 | + var hitsTime = List[(Date, Int)]() |
| 88 | + var missesTime = List[(Date, Int)]() |
| 89 | + |
| 90 | + var scoredMatches = List[Int]() |
| 91 | + var falseTippMatches = List[Int]() |
| 92 | + var missedMatches = List[Int]() |
| 93 | + |
| 94 | + //Iterate over all played matches backwards for efficiency. Will crash on failure, which is ok. |
| 95 | + for { |
| 96 | + m <- Match.playedMatches.reverse |
| 97 | + score = tipps.find(m.id == _.matchId) match { |
| 98 | + case Some(tipp) => getPointsForTipp(m, tipp) |
| 99 | + case None => -1 // A game where no tipp exists |
| 100 | + } |
| 101 | + }{ |
| 102 | + points += score |
| 103 | + score match { |
| 104 | + case -1 => { |
| 105 | + missed += 1 |
| 106 | + missedMatches ::= m.id |
| 107 | + } |
| 108 | + case 0 => { |
| 109 | + falseTipps += 1 |
| 110 | + falseTippMatches::= m.id |
| 111 | + } |
| 112 | + case 2 => { |
| 113 | + tendencies += 1 |
| 114 | + scoredMatches ::= m.id |
| 115 | + } |
| 116 | + case 3 => { |
| 117 | + diffs += 1 |
| 118 | + scoredMatches ::= m.id |
| 119 | + } |
| 120 | + case 4 => { |
| 121 | + hits +=1 |
| 122 | + scoredMatches ::= m.id |
| 123 | + } |
| 124 | + } |
| 125 | + pointsTime ::= (m.date, points) |
| 126 | + tendenciesTime ::= (m.date, tendencies) |
| 127 | + diffsTime ::= (m.date, diffs) |
| 128 | + hitsTime ::= (m.date, hits) |
| 129 | + missesTime ::= (m.date, falseTipps) |
| 130 | + } |
| 131 | + |
| 132 | + new Stats(playerId, |
| 133 | + scoredMatches, |
| 134 | + falseTippMatches, |
| 135 | + missedMatches, |
| 136 | + points, |
| 137 | + pointsTime, |
| 138 | + tendencies, |
| 139 | + tendenciesTime, |
| 140 | + diffs, |
| 141 | + diffsTime, |
| 142 | + hits, |
| 143 | + hitsTime |
| 144 | + ) |
| 145 | + } |
| 146 | + |
| 147 | + |
| 148 | + def getPointsForTipp(m: Match, tipp: Tipp): Int = { |
| 149 | + assert(m.id == tipp.matchId) |
| 150 | + |
| 151 | + val diffMatch = (m.scoreA - m.scoreB) |
| 152 | + val diffTipp = (tipp.scoreA - tipp.scoreB) |
| 153 | + |
| 154 | + if (m.scoreA == tipp.scoreA && m.scoreB == tipp.scoreB){ |
| 155 | + 4 |
| 156 | + } else if (diffMatch != 0 && diffMatch == diffTipp) { |
| 157 | + 3 |
| 158 | + } else if (diffMatch > 0 && diffTipp >0 || diffMatch < 0 && diffTipp < 0 || diffMatch == 0 && diffTipp == 0){ |
| 159 | + 2 |
| 160 | + } else { |
| 161 | + 0 |
| 162 | + } |
| 163 | + } |
| 164 | +} |
| 165 | + |
| 166 | +case class Stats( playerId: String, |
| 167 | + scoredMatches: List[Int], // List of MatchIDs where the player scored |
| 168 | + falseTippMatches: List[Int], // List of MatchIDs where the player missed |
| 169 | + missedMatches: List[Int], // List of games which weren't tipped for |
| 170 | + points: Int, |
| 171 | + pointsTimeseries: List[(Date, Int)], |
| 172 | + tendencies: Int, |
| 173 | + tendenciesTimeseries: List[(Date, Int)], |
| 174 | + diffs: Int, |
| 175 | + diffsTimeseries: List[(Date, Int)], |
| 176 | + hits: Int, |
| 177 | + hitsTimeseries: List[(Date, Int)] |
| 178 | + ) { |
| 179 | + |
| 180 | + override def toString = { |
| 181 | + s"Player: ${playerId} has ${points} points from ${scoredMatches.length} scored matches. ($tendencies tends, " + |
| 182 | + s" $diffs diffs and $hits hits)" |
| 183 | + } |
| 184 | +} |
| 185 | + |
| 186 | + |
| 187 | +case class Player(firstName: String, lastName: String, nickName: String, email: String, tipps: List[Tipp]){ |
| 188 | + val id = firstName + lastName + nickName |
| 189 | + lazy val gamesTipped = Match.playedMatches |
| 190 | + val results = Tipp.evaluateTipps(tipps, id) |
| 191 | +} |
| 192 | + |
| 193 | +object Player { |
| 194 | + lazy val allPlayers = Retrieval.getAllPlayers |
| 195 | + |
| 196 | +} |
| 197 | + |
| 198 | + |
| 199 | + |
| 200 | + |
| 201 | + |
| 202 | + |
| 203 | + |
| 204 | + |
| 205 | + |
| 206 | + |
| 207 | + |
| 208 | + |
| 209 | + |
| 210 | + |
| 211 | + |
| 212 | + |
| 213 | + |
| 214 | + |
| 215 | +//object Data { |
| 216 | + |
| 217 | +// val (games, groups) = parseTable("src/main/resources/teams.csv") |
| 218 | +// val responses = parseResponses("src/main/resources/responses.csv") |
| 219 | +// |
| 220 | +// def main(args: Array[String]) = { |
| 221 | +// //println(responses) |
| 222 | +// |
| 223 | +// } |
| 224 | +// |
| 225 | +// def parseResponses(filename: String): List[Player]= { |
| 226 | +// val rawData = scala.io.Source.fromFile(filename).getLines |
| 227 | +// val header = rawData.next |
| 228 | +// |
| 229 | +// def parseSingleResponse(response: List[String]): Player = { |
| 230 | +// val firstName = response(1) |
| 231 | +// val lastName = response(2) |
| 232 | +// val nickName = response(3) |
| 233 | +// val email = response(4) |
| 234 | +// |
| 235 | +// val first = response(response.length - 3 ) |
| 236 | +// val second = response(response.length - 2) |
| 237 | +// val third = response(response.length - 1) |
| 238 | +// |
| 239 | +// var index = 0 |
| 240 | +// val tipps = for{ |
| 241 | +// tipp <- response.drop(5) |
| 242 | +// tipps = tipp.split(':').toList.map(_.toInt) |
| 243 | +// } yield(new Tipp( |
| 244 | +// games(index), |
| 245 | +// tipps(0), |
| 246 | +// tipps(1) |
| 247 | +// )) |
| 248 | +// new Player(firstName, lastName, nickName, email, tipps.toList) |
| 249 | +// } |
| 250 | +// |
| 251 | +// (for{ |
| 252 | +// responseLine <- rawData |
| 253 | +// response = responseLine.split(',').toList if(!response.isEmpty) |
| 254 | +// } yield(parseSingleResponse(response))).toList |
| 255 | +// } |
| 256 | +// |
| 257 | +// def parseTable(filename: String) = { |
| 258 | +// val start = System.currentTimeMillis |
| 259 | +// |
| 260 | +// // import the csv file |
| 261 | +// val rawData = scala.io.Source.fromFile(filename).getLines.toList |
| 262 | +// |
| 263 | +// def parseTeams: Set[Team] = { |
| 264 | +// val firstLine = rawData.head.split(',').toList |
| 265 | +// (for{ |
| 266 | +// (team, pos) <- firstLine.zipWithIndex |
| 267 | +// } yield new Team(team, ('A' + pos/6).toChar)).toSet |
| 268 | +// } |
| 269 | +// |
| 270 | +// val teams = parseTeams |
| 271 | +// |
| 272 | +// |
| 273 | +// |
| 274 | +// def parseGames: List[Game] = { |
| 275 | +// // A mapping for all the timezones |
| 276 | +// val timezones = Map( |
| 277 | +// "Sao Paulo" -> "GMT-03:00", |
| 278 | +// "Natal" -> "GMT-03:00", |
| 279 | +// "Fortaleza" -> "GMT-03:00", |
| 280 | +// "Manaus" -> "GMT-4:00", |
| 281 | +// "Brasilia" -> "GMT-3:00", |
| 282 | +// "Recife" -> "GMT-3:00", |
| 283 | +// "Salvador" -> "GMT-3:00", |
| 284 | +// "Cuiaba" -> "GMT-4:00", |
| 285 | +// "Porto Alegre" -> "GMT-3:00", |
| 286 | +// "Rio de Janeiro" -> "GMT-3:00", |
| 287 | +// "Curitiba" -> "GMT-3:00", |
| 288 | +// "Belo Horizonte" -> "GMT-3:00" |
| 289 | +// ) |
| 290 | +// |
| 291 | +// // Get all the games in the initial round of the tournament |
| 292 | +// val teamsA = rawData(0).split(',').toList |
| 293 | +// val teamsB = rawData(1).split(',').toList |
| 294 | +// val dates = rawData(2).split(',').toList |
| 295 | +// val times = rawData(3).split(',').toList |
| 296 | +// val places = rawData(4).split(',').toList |
| 297 | +// |
| 298 | +// val dateFormat = new java.text.SimpleDateFormat("dd.MM.yyyy-hh") |
| 299 | +// |
| 300 | +// // Create all the games and see which ones were played yet |
| 301 | +// (for { |
| 302 | +// (teamA, pos) <- teamsA.zipWithIndex |
| 303 | +// teamAA = teams.find(_.name == teamA).get |
| 304 | +// teamB = teams.find(_.name == teamsB(pos)).get |
| 305 | +// place = places(pos) |
| 306 | +// date = { |
| 307 | +// dateFormat.setTimeZone(TimeZone.getTimeZone(timezones(place))) |
| 308 | +// dateFormat.parse(s"${dates(pos)}-${times(pos).split(':').head}") |
| 309 | +// } |
| 310 | +// played = { |
| 311 | +// date.before(new java.util.Date(System.currentTimeMillis + (1000 * 60 * 60 * 4))) |
| 312 | +// } |
| 313 | +// } yield new Game(teamAA, |
| 314 | +// teamB, |
| 315 | +// teamAA.group, |
| 316 | +// date, |
| 317 | +// place, |
| 318 | +// played)).toList.sortBy(_.date) |
| 319 | +// } |
| 320 | +// |
| 321 | +// val games = parseGames |
| 322 | +// |
| 323 | +// for { |
| 324 | +// game <- games if (game.isDone) |
| 325 | +// } (getResult(game)) |
| 326 | +// |
| 327 | +// |
| 328 | +// // TODO make this a little more sophisticated |
| 329 | +// def getResult(game: Game) = { |
| 330 | +// game.scoreA = 100 |
| 331 | +// game.scoreB = 100 |
| 332 | +// } |
| 333 | +// |
| 334 | +// def makeGroups: List[Group] = { |
| 335 | +// val mapping = teams.groupBy(_.group) |
| 336 | +// (for{ |
| 337 | +// groupName <- mapping.keys |
| 338 | +// } yield new Group(groupName, |
| 339 | +// mapping(groupName), |
| 340 | +// games.filter(_.group == groupName))).toList.sortBy(_.name) |
| 341 | +// } |
| 342 | +// |
| 343 | +// val groups = makeGroups |
| 344 | +// val time = System.currentTimeMillis() - start |
| 345 | +// println(s"<<<<< Run took $time ms >>>>>") |
| 346 | +// (games, makeGroups) |
| 347 | +// } |
| 348 | + |
| 349 | + |
| 350 | +//} |
| 351 | + |
0 commit comments