Skip to content

Commit

Permalink
more tournament smart pairings
Browse files Browse the repository at this point in the history
  • Loading branch information
ornicar committed Dec 16, 2015
1 parent 4d4a4b7 commit 439af06
Show file tree
Hide file tree
Showing 4 changed files with 16 additions and 28 deletions.
2 changes: 1 addition & 1 deletion modules/tournament/src/main/Socket.scala
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ private[tournament] final class Socket(
case Reload => notifyReload

case GetWaitingUsers =>
waitingUsers = waitingUsers.update(userIds, clock)
waitingUsers = waitingUsers.update(userIds.toSet, clock)
sender ! waitingUsers

case PingVersion(uid, v) => {
Expand Down
4 changes: 3 additions & 1 deletion modules/tournament/src/main/WaitingUsers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ private[tournament] case class WaitingUsers(
}.toList
}

def update(us: Seq[String], clock: Option[chess.Clock]) = {
def update(us: Set[String], clock: Option[chess.Clock]) = {
val newDate = DateTime.now
copy(
date = newDate,
Expand All @@ -50,6 +50,8 @@ private[tournament] case class WaitingUsers(
def intersect(us: Seq[String]) = copy(hash = hash filterKeys us.contains)

def diff(us: Set[String]) = copy(hash = hash filterKeys { k => !us.contains(k) })

override def toString = all.toString
}

private[tournament] object WaitingUsers {
Expand Down
36 changes: 11 additions & 25 deletions modules/tournament/src/main/arena/PairingSystem.scala
Original file line number Diff line number Diff line change
Expand Up @@ -32,41 +32,27 @@ object PairingSystem extends AbstractPairingSystem {
pairings <- preps.map { prep =>
UserRepo.firstGetsWhite(prep.user1.some, prep.user2.some) map prep.toPairing
}.sequenceFu
} yield {
if (tour.nbPlayers > 50) logRematch(tour, pairings, recentPairings)
pairings
}

private def logRematch(tour: Tournament, pairings: Pairings, recent: Pairings) {
pairings.foreach { p =>
List(
recent find { _ contains p.user1 },
recent find { _ contains p.user2 }
).flatten.filter(p.similar).distinct foreach { r =>
play.api.Logger("tourpairing").warn(
s"rematch https://lichess.org/tournament/${tour.id} ${p.id} ${p.user1} vs ${p.user2} like ${r.id}")
}
}
}
} yield pairings

private def evenOrAll(data: Data, users: WaitingUsers) =
makePreps(data, users.evenNumber) flatMap {
case Nil if users.isOdd => makePreps(data, users.all)
case x => fuccess(x)
}

val smartHardLimit = 22
val overallLimit = 40
val extraNaiveLimit = overallLimit - smartHardLimit
val pairingGroupSize = 20

private def makePreps(data: Data, users: List[String]): Fu[List[Pairing.Prep]] = {
import data._
if (users.size < 2) fuccess(Nil)
else PlayerRepo.rankedByTourAndUserIds(tour.id, users, ranking) map { idles =>
if (recentPairings.isEmpty) naivePairings(tour, idles)
else
smartPairings(data, idles take smartHardLimit) :::
naivePairings(tour, idles drop smartHardLimit take extraNaiveLimit)
else idles.grouped(pairingGroupSize).toList match {
case a :: b :: c :: _ => smartPairings(data, a) ::: smartPairings(data, b) ::: naivePairings(tour, c take pairingGroupSize)
case a :: b :: Nil => smartPairings(data, a) ::: smartPairings(data, b)
case a :: Nil => smartPairings(data, a)
case Nil => Nil
}
}
}

Expand All @@ -75,7 +61,7 @@ object PairingSystem extends AbstractPairingSystem {
case List(p1, p2) => Pairing.prep(tour, p1.player, p2.player)
} toList

private def smartPairings(data: Data, players: RankedPlayers): List[Pairing.Prep] = {
private def smartPairings(data: Data, players: RankedPlayers): List[Pairing.Prep] = players.nonEmpty ?? {
import data._

type Score = Int
Expand All @@ -89,10 +75,10 @@ object PairingSystem extends AbstractPairingSystem {
}.toMap

def justPlayedTogether(u1: String, u2: String): Boolean =
lastOpponents.get(u1).exists(u2==) || lastOpponents.get(u2).exists(u1==)
lastOpponents.get(u1).contains(u2) || lastOpponents.get(u2).contains(u1)

def veryMuchJustPlayedTogether(u1: String, u2: String): Boolean =
lastOpponents.get(u1).exists(u2==) && lastOpponents.get(u2).exists(u1==)
lastOpponents.get(u1).contains(u2) && lastOpponents.get(u2).contains(u1)

// lower is better
def pairingScore(pair: RankedPairing): Score = pair match {
Expand Down
2 changes: 1 addition & 1 deletion modules/tournament/src/main/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ package tournament {

case class RankedPlayer(rank: Int, player: Player) {
def is(other: RankedPlayer) = player is other.player
override def toString = s"${player.userId}[${player.rating}]"
override def toString = s"$rank. ${player.userId}[${player.rating}]"
}

case class Winner(tourId: String, tourName: String, userId: String)
Expand Down

0 comments on commit 439af06

Please sign in to comment.