HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

Akka actor to calculate a soccer league rank

Submitted by: @import:stackexchange-codereview··
0
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:

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).

  • 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.