/*
* 1. Why is the list of rounds being processed in reverse order?
* 2. Why is the whole list of rounds being swapped to calculate
* player 2's score? Use Tuple2.
* 3. Why does a "small" class/concept _Move_ have access to _Round_?
* 3.5 Why is the whole round log being passed as a parameter?
* Because we really want the previous move.
* 4. There is no Nothing/Default move, forcing us to use Nil...
* 5. The variable names need to be more explicative.
*/
package exp;
object PrisonersDilemma2 {
sealed abstract class Move
case object StartGame extends Move
case object Cooperate extends Move
case object Defect extends Move
trait MoveStrategy {
def nextMove (opponent: Move): Move
}
class AlwaysDefect extends MoveStrategy {
def nextMove (opponent: Move) = Defect
}
class AlwaysCooperate extends MoveStrategy {
def nextMove (opponent: Move) = Cooperate
}
class TitForTat extends MoveStrategy {
def nextMove (opponent: Move) =
if (opponent == StartGame) Cooperate else opponent
}
class Game (p1: MoveStrategy, p2: MoveStrategy, moves: Int) {
private var rounds: List[(Move,Move)] = List();
private var previousMove: Move = StartGame;
for (_ <- 1 to moves)
previousMove = playRound (previousMove);
protected def playRound (previousMove: Move): Move = {
val p1move: Move = p1.nextMove (previousMove);
val p2move: Move = p2.nextMove (p1move);
rounds = rounds :+ (p1move, p2move);
p2move;
}
protected def getScore (round: (Move, Move)): Int = round match {
case (Cooperate,Cooperate) => 3
case (Cooperate,Defect) => 0
case (Defect,Cooperate) => 5
case (Defect,Defect) => 1
case default => 0
}
protected def getPlayer1Score: Int =
rounds.map {getScore(_)}.sum;
protected def getPlayer2Score: Int =
rounds.map {r: (Move, Move) => getScore((r._2, r._1))}.sum;
override def toString: String =
"Game [\r\n" + rounds.mkString(" ", ",\r\n ", "\r\n") + "]\r\n";
def getScore: (Int, Int) = (getPlayer1Score, getPlayer2Score);
} // Game
def main (args: Array[String]) = {
val titForTat = new TitForTat ();
val alwaysDefect = new AlwaysDefect ();
val game = new Game (titForTat, alwaysDefect, 10);
println (game);
println (s"Final Score: ${game.getScore}");
} // main
} // PrisonersDilemma2