Skip to content

Instantly share code, notes, and snippets.

@AliceCengal
Last active August 29, 2015 14:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AliceCengal/c93c3661901b6a83987e to your computer and use it in GitHub Desktop.
Save AliceCengal/c93c3661901b6a83987e to your computer and use it in GitHub Desktop.
/* Simulate Swiss tournament
* Usage: pipe https://raw.githubusercontent.com/hadley/data-baby-names/master/baby-names.csv
* into the script's standard input */
import scala.io.Codec.UTF8
import scala.util.Random
object Tournament {
type ScoreMx = Array[Array[Array[Int]]]
def bonusify(baseScore: Int)(implicit random: Random) = {
baseScore + random.nextInt(11) - 5
}
def matchResult()(implicit random: Random) = {
val win = random.nextInt(3) - 1 // [-1, 1]
List(10 + (5 * win), 10 - (5 * win)).map { bonusify(_) }
}
}
class Tournament(player_n: Int, round_n: Int) {
assert(player_n > 1 && round_n > 1)
import Tournament._
val scores: ScoreMx = Array.fill(player_n, player_n, round_n)(0)
val players = (0 until player_n)
val rounds = (0 until round_n)
implicit val random = new Random
def hasPlayedEachOther(p1: Int, p2: Int): Boolean = {
scores(p1)(p2).sum.>(0)
}
def scoresInRounds(p: Int): List[Int] = {
rounds.map { r => players.map { p2 => scores(p)(p2)(r) }
.sum}
.toList
}
def totalScore(p: Int): Int = scoresInRounds(p).sum
def randomPairing(): List[Int] = random.shuffle(players.toList)
def scoreBasedPairing: List[Int] = {
val sorted = players.toArray.sortBy(totalScore(_)).reverse
for (i <- players by 2) {
var j = i + 1
while (hasPlayedEachOther(sorted(i), sorted(j))) { j = j + 1 }
val tmp = sorted(j)
sorted(j) = sorted(i + 1)
sorted(i + 1) = tmp
}
sorted.toList
}
def matchUp(p1: Int, p2: Int, round: Int): Unit = {
val res = matchResult()
scores(p1)(p2)(round) = res(0)
scores(p2)(p1)(round) = res(1)
}
def play(): Unit = {
firstRound()
rounds.drop(1).foreach { r => normalRound(r) }
}
def firstRound(): Unit = {
randomPairing().grouped(2).foreach { case p1 :: p2 :: _ =>
matchUp(p1, p2, 0)
}
}
def normalRound(round: Int): Unit = {
scoreBasedPairing.grouped(2).foreach { case p1 :: p2 :: _ =>
matchUp(p1, p2, round)
}
}
}
def printCell(values: Seq[Seq[String]]) {
val maxLength = values.flatMap( row => row.map(_.length)).max
values.foreach { row => println(row.map(_.padTo(maxLength + 1, ' ')).mkString) }
}
val firsts = io.Source.stdin.getLines.drop(1)
.map(_.split("\"*,\"*").apply(1)) // assume specific format. see notes above
.toArray
val names = (new Random).shuffle(firsts.toList).take(32)
val tourney = new Tournament(32, 6)
tourney.play()
val rows = tourney.players.toList
.sortBy(tourney.totalScore(_)).reverse
.map { p => p :: tourney.scoresInRounds(p) ::: List(tourney.totalScore(p)) }
.map(_.map(_.toString))
val taggedRows = (1 to 32).toList.zip(names).zip(rows).map {
case ((rank, name), scores) => rank.toString :: name :: scores }
val headers = List("Rank", "Player", "ID", "Rnd1", "Rnd2", "Rnd3", "Rnd4", "Rnd5", "Rnd6", "Total")
printCell(headers :: taggedRows)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment