Last active
August 29, 2015 14:03
-
-
Save AliceCengal/c93c3661901b6a83987e to your computer and use it in GitHub Desktop.
My solution for http://www.reddit.com/r/dailyprogrammer/comments/2afwlj/7112014_challenge_170_hard_swiss_tournament_with/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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