patternMinor
Akka actor to calculate a soccer league rank
Viewed 0 times
actorsoccerrankakkacalculateleague
Problem
I am new to Scala / Akka and this is my first attempt at writing an actor.
The task that I am trying to accomplish is: given a sequence of soccer matches, generate a ranking based on the usual rules of soccer (winner gets 3 points, loser gets 0 points, and 1 point each in case of a draw).
Here is my current ranker actor:
I have a few supporting case classes:
```
case class MatchResult(team1: String, score1: Int, team2: String, s
The task that I am trying to accomplish is: given a sequence of soccer matches, generate a ranking based on the usual rules of soccer (winner gets 3 points, loser gets 0 points, and 1 point each in case of a draw).
Here is my current ranker actor:
package soccerLeague.akka
import akka.actor.Actor
import soccerLeague.common.{LeagueRules, MatchResult, TeamWithPoints}
// Stateful Ranker actor that maintains a rank.
// The rank gets updated every time a MatchResult message is received.
class RankerActor(rules: LeagueRules) extends Actor {
private var rank: Seq[TeamWithPoints] = List()
private var rankMap = Map[String, Int]()
def receive = {
case MatchResult(team1, score1, team2, score2) => {
updateRank(MatchResult(team1, score1, team2, score2))
sender ! rank
}
case Message("getRank") => {
sender ! rank
}
}
private def updateRank(matchRes: MatchResult): Unit = {
def calcDeltaPoints(score1: Int, score2: Int): Int = {
if(score1 == score2) rules.drawScore
else if(score1 > score2) rules.winScore
else rules.lossScore
}
val newPoints1 = rankMap.getOrElse(matchRes.team1, 0) + calcDeltaPoints(matchRes.score1, matchRes.score2)
val newPoints2 = rankMap.getOrElse(matchRes.team2, 0) + calcDeltaPoints(matchRes.score2, matchRes.score1)
rankMap += (matchRes.team1 -> newPoints1, matchRes.team2 -> newPoints2)
// Sort by score, in reverse order (i.e. the team with most points is first).
// Teams that have the same score are sorted in alphabetical order.
// TODO: this *can* be improved by only moving around the two teams that are changing.
rank = rankMap.toSeq
.map { case (t, s) => new TeamWithPoints(t, s) }
.sortBy { case TeamWithPoints(team, points) => (-points, team) }
}
}I have a few supporting case classes:
```
case class MatchResult(team1: String, score1: Int, team2: String, s
Solution
For starters you could try sending commands to you Actor instead of Nouns(source: Reactive Messaging Patterns with the Actor Model).
See this thread for information on naming Commands.
https://stackoverflow.com/questions/12510535/naming-convention-for-commands-events
- Put commands into a companion object for Actor.
- Name commands in past tense.
- Remove your "literal match" [Message("getRank")] and create a Command(type-safet) to handle the method.
See this thread for information on naming Commands.
https://stackoverflow.com/questions/12510535/naming-convention-for-commands-events
Context
StackExchange Code Review Q#157857, answer score: 2
Revisions (0)
No revisions yet.