Skip to content

Commit

Permalink
prevent bot farming - closes #4839
Browse files Browse the repository at this point in the history
  • Loading branch information
ornicar committed Jan 22, 2019
1 parent 21dec04 commit cf3f27f
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 4 deletions.
33 changes: 33 additions & 0 deletions modules/round/src/main/BotFarming.scala
@@ -0,0 +1,33 @@
package lila.round

import lila.common.LightUser.IsBotSync
import lila.game.{ Game, GameRepo, CrosstableApi }

private final class BotFarming(
crosstableApi: CrosstableApi,
isBotSync: IsBotSync
) {

val SAME_PLIES = 20
val PREV_GAMES = 2

/* true if
* - at least one bot
* - rated
* - recent game in same matchup has same first SAME_PLIES and same winner
*/
def apply(g: Game): Fu[Boolean] = g.userIds.distinct match {
case List(u1, u2) if g.finished && g.rated && g.userIds.exists(isBotSync) =>
crosstableApi(u1, u2) flatMap {
_ ?? { ct =>
GameRepo.gamesFromSecondary(ct.results.reverse.take(PREV_GAMES).map(_.gameId)) map {
_ exists { prev =>
g.winnerUserId == prev.winnerUserId &&
g.pgnMoves.take(SAME_PLIES) == prev.pgnMoves.take(SAME_PLIES)
}
}
}
}
case _ => fuccess(false)
}
}
4 changes: 3 additions & 1 deletion modules/round/src/main/Env.scala
Expand Up @@ -152,7 +152,9 @@ final class Env(
isRecentTv = recentTvGames get _
)

lazy val perfsUpdater = new PerfsUpdater(historyApi, rankingApi)
private lazy val botFarming = new BotFarming(crosstableApi, isBotSync)

lazy val perfsUpdater = new PerfsUpdater(historyApi, rankingApi, botFarming)

lazy val forecastApi: ForecastApi = new ForecastApi(
coll = db(CollectionForecast),
Expand Down
9 changes: 6 additions & 3 deletions modules/round/src/main/PerfsUpdater.scala
Expand Up @@ -10,16 +10,18 @@ import lila.user.{ UserRepo, User, Perfs, RankingApi }

final class PerfsUpdater(
historyApi: HistoryApi,
rankingApi: RankingApi
rankingApi: RankingApi,
botFarming: BotFarming
) {

private val VOLATILITY = Glicko.default.volatility
private val TAU = 0.75d
private val system = new RatingCalculator(VOLATILITY, TAU)

// returns rating diffs
def save(game: Game, white: User, black: User): Fu[Option[RatingDiffs]] =
PerfPicker.main(game) ?? { mainPerf =>
def save(game: Game, white: User, black: User): Fu[Option[RatingDiffs]] = botFarming(game) flatMap {
case true => fuccess(none)
case _ => PerfPicker.main(game) ?? { mainPerf =>
(game.rated && game.finished && game.accountable && !white.lame && !black.lame) ?? {
val ratingsW = mkRatings(white.perfs)
val ratingsB = mkRatings(black.perfs)
Expand Down Expand Up @@ -73,6 +75,7 @@ final class PerfsUpdater(
rankingApi.save(black, game.perfType, perfsB) inject ratingDiffs.some
}
}
}

private final case class Ratings(
chess960: Rating,
Expand Down

0 comments on commit cf3f27f

Please sign in to comment.